openlimits_binance/client/
account.rs1use std::collections::HashMap;
2use rust_decimal::prelude::*;
3use serde_json::json;
4use crate::model::{AccountInformation, AllOrderReq, Balance, Order, ORDER_SIDE_BUY, ORDER_SIDE_SELL, ORDER_TYPE_LIMIT, ORDER_TYPE_LIMIT_MAKER, ORDER_TYPE_MARKET, OrderCanceled, OrderRequest, TimeInForce, TradeHistory, TradeHistoryReq, MarketPair};
5use openlimits_exchange::errors::OpenLimitsError;
6use openlimits_exchange::traits::info::MarketPairInfo;
7use super::BaseClient;
8use super::shared::Result;
9
10impl BaseClient {
11 pub async fn get_account(&self) -> Result<AccountInformation> {
13 let account_info = self
14 .transport
15 .signed_get::<_, ()>("/api/v3/account", None)
16 .await?;
17
18 Ok(account_info)
19 }
20
21 pub async fn get_balance(&self, asset: &str) -> Result<Balance> {
23 let asset = asset.to_string();
24 let search = move |account: AccountInformation| -> Result<Balance> {
25 let balance = account
26 .balances
27 .into_iter()
28 .find(|balance| balance.asset == asset)
29 .ok_or(OpenLimitsError::AssetNotFound())?;
30
31 Ok(balance)
32 };
33
34 self.get_account().await.and_then(search)
35 }
36
37 pub async fn get_open_orders(&self, symbol: &str) -> Result<Vec<Order>> {
39 let params: HashMap<&str, String> =
40 [("symbol", String::from(symbol))].iter().cloned().collect();
41 let orders = self
42 .transport
43 .signed_get("/api/v3/openOrders", Some(¶ms))
44 .await?;
45 Ok(orders)
46 }
47
48 pub async fn get_all_open_orders(&self) -> Result<Vec<Order>> {
50 let orders = self
51 .transport
52 .signed_get::<_, ()>("/api/v3/openOrders", None)
53 .await?;
54 Ok(orders)
55 }
56
57 pub async fn get_all_orders(&self, params: &AllOrderReq) -> Result<Vec<Order>> {
58 let orders = self
59 .transport
60 .signed_get("/api/v3/allOrders", Some(params))
61 .await?;
62 Ok(orders)
63 }
64
65 pub async fn get_order(&self, symbol: &str, order_id: u64) -> Result<Order> {
66 let params = json! {{"symbol": symbol, "orderId": order_id}};
67
68 let order = self
69 .transport
70 .signed_get("/api/v3/order", Some(¶ms))
71 .await?;
72 Ok(order)
73 }
74
75 pub async fn limit_buy(
77 &self,
78 pair: MarketPairInfo,
79 qty: Decimal,
80 price: Decimal,
81 tif: TimeInForce,
82 post_only: bool,
83 ) -> Result<Order> {
84 let (order_type, time_in_force) = match post_only {
85 true => (ORDER_TYPE_LIMIT_MAKER.to_string(), None),
86 false => (ORDER_TYPE_LIMIT.to_string(), Some(tif)),
87 };
88
89 let buy: OrderRequest = OrderRequest {
90 symbol: pair.symbol,
91 quantity: qty.round_dp(pair.base_increment.normalize().scale()),
92 price: Some(price.round_dp_with_strategy(
93 pair.quote_increment.normalize().scale(),
94 RoundingStrategy::ToZero,
95 )),
96 order_side: ORDER_SIDE_BUY.to_string(),
97 order_type,
98 time_in_force,
99 };
100
101 let transaction = self
102 .transport
103 .signed_post("/api/v3/order", Some(&buy))
104 .await?;
105
106 Ok(transaction)
107 }
108
109 pub async fn limit_sell(
112 &self,
113 pair: MarketPairInfo,
114 qty: Decimal,
115 price: Decimal,
116 tif: TimeInForce,
117 post_only: bool,
118 ) -> Result<Order> {
119 let (order_type, time_in_force) = match post_only {
120 true => (ORDER_TYPE_LIMIT_MAKER.to_string(), None),
121 false => (ORDER_TYPE_LIMIT.to_string(), Some(tif)),
122 };
123
124 let sell: OrderRequest = OrderRequest {
125 symbol: pair.symbol,
126 quantity: qty.round_dp(pair.base_increment.normalize().scale()),
127 price: Some(price.round_dp_with_strategy(
128 pair.quote_increment.normalize().scale(),
129 RoundingStrategy::AwayFromZero,
130 )),
131 order_side: ORDER_SIDE_SELL.to_string(),
132 order_type,
133 time_in_force,
134 };
135
136 let transaction = self
137 .transport
138 .signed_post("/api/v3/order", Some(&sell))
139 .await?;
140
141 Ok(transaction)
142 }
143
144 pub async fn market_buy(&self, pair: MarketPairInfo, qty: Decimal) -> Result<Order> {
146 let buy: OrderRequest = OrderRequest {
147 symbol: pair.symbol,
148 quantity: qty.round_dp(pair.base_increment.normalize().scale()),
149 price: None,
150 order_side: ORDER_SIDE_BUY.to_string(),
151 order_type: ORDER_TYPE_MARKET.to_string(),
152 time_in_force: None,
153 };
154
155 let transaction = self
156 .transport
157 .signed_post("/api/v3/order", Some(&buy))
158 .await?;
159
160 Ok(transaction)
161 }
162
163 pub async fn market_sell(&self, pair: MarketPairInfo, qty: Decimal) -> Result<Order> {
165 let sell: OrderRequest = OrderRequest {
166 symbol: pair.symbol,
167 quantity: qty.round_dp(pair.base_increment.normalize().scale()),
168 price: None,
169 order_side: ORDER_SIDE_SELL.to_string(),
170 order_type: ORDER_TYPE_MARKET.to_string(),
171 time_in_force: None,
172 };
173
174 let transaction = self
175 .transport
176 .signed_post("/api/v3/order", Some(&sell))
177 .await?;
178 Ok(transaction)
179 }
180
181 pub async fn cancel_order(&self, symbol: &str, order_id: u64) -> Result<OrderCanceled> {
183 let params = json! {{"symbol":symbol, "orderId":order_id}};
184 let order_canceled = self
185 .transport
186 .signed_delete("/api/v3/order", Some(¶ms))
187 .await?;
188 Ok(order_canceled)
189 }
190
191 pub async fn cancel_all_orders<P: Into<MarketPair>>(&self, symbol: P) -> Result<Vec<OrderCanceled>> {
192 let symbol = symbol.into().0;
193 let params = json! {{"symbol":symbol}};
194 let orders_canceled = self
195 .transport
196 .signed_delete("/api/v3/openOrders", Some(¶ms))
197 .await?;
198 Ok(orders_canceled)
199 }
200
201 pub async fn trade_history(&self, params: &TradeHistoryReq) -> Result<Vec<TradeHistory>> {
203 let trade_history = self
204 .transport
205 .signed_get("/api/v3/myTrades", Some(params))
206 .await?;
207
208 Ok(trade_history)
209 }
210}