Skip to main content

openlimits_binance/client/
account.rs

1use 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    // Account Information
12    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    // Balance for ONE Asset
22    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    // Current open orders for ONE symbol
38    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(&params))
44            .await?;
45        Ok(orders)
46    }
47
48    // All current open orders
49    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(&params))
71            .await?;
72        Ok(order)
73    }
74
75    // Place a LIMIT order - BUY
76    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    // Place a LIMIT order - SELL
110
111    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    // Place a MARKET order - BUY
145    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    // Place a MARKET order - SELL
164    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    // Check an order's status
182    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(&params))
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(&params))
197            .await?;
198        Ok(orders_canceled)
199    }
200
201    // Trade history
202    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}