ecbt_coinbase/client/
account.rs

1use super::shared::Result;
2use super::BaseClient;
3use crate::model::MarketPair;
4use crate::model::{
5    Account, CancelAllOrders, CancelOrder, Fill, GetFillsReq, GetOrderRequest, Order, OrderRequest,
6    OrderRequestMarketType, OrderRequestType, OrderSide, OrderTimeInForce, Paginator,
7};
8use ecbt_exchange::info::MarketPairInfo;
9use rust_decimal::prelude::*;
10
11impl BaseClient {
12    pub async fn get_account(&self, paginator: Option<&Paginator>) -> Result<Vec<Account>> {
13        self.transport.signed_get("/accounts", paginator).await
14    }
15
16    pub async fn get_orders(&self, params: Option<&GetOrderRequest>) -> Result<Vec<Order>> {
17        self.transport.signed_get::<_, _>("/orders", params).await
18    }
19
20    pub async fn get_order(&self, order_id: String) -> Result<Order> {
21        self.transport
22            .signed_get::<_, ()>(&format!("/orders/{}", order_id), None)
23            .await
24    }
25
26    // TODO: refactor buy and sell in order creation in commun function
27    pub async fn market_buy(&self, pair: MarketPairInfo, size: Decimal) -> Result<Order> {
28        let data = OrderRequest {
29            product_id: pair.symbol,
30            client_oid: None,
31            side: OrderSide::Buy,
32            _type: OrderRequestType::Market {
33                _type: OrderRequestMarketType::Size {
34                    size: size.round_dp(pair.base_increment.normalize().scale()),
35                },
36            },
37            stop: None,
38        };
39
40        let transaction = self
41            .transport
42            .signed_post::<_, (), _>("/orders", None, Some(&data))
43            .await?;
44
45        Ok(transaction)
46    }
47
48    pub async fn market_sell(&self, pair: MarketPairInfo, size: Decimal) -> Result<Order> {
49        let data = OrderRequest {
50            product_id: pair.symbol,
51            client_oid: None,
52            side: OrderSide::Sell,
53            _type: OrderRequestType::Market {
54                _type: OrderRequestMarketType::Size {
55                    size: size.round_dp(pair.base_increment.normalize().scale()),
56                },
57            },
58            stop: None,
59        };
60
61        let transaction = self
62            .transport
63            .signed_post::<_, (), _>("/orders", None, Some(&data))
64            .await?;
65
66        Ok(transaction)
67    }
68
69    pub async fn limit_buy(
70        &self,
71        pair: MarketPairInfo,
72        size: Decimal,
73        price: Decimal,
74        time_in_force: OrderTimeInForce,
75        post_only: bool,
76    ) -> Result<Order> {
77        let data = OrderRequest {
78            product_id: pair.symbol,
79            client_oid: None,
80            side: OrderSide::Buy,
81            _type: OrderRequestType::Limit {
82                size: size.round_dp(pair.base_increment.normalize().scale()),
83                price: price.round_dp_with_strategy(
84                    pair.quote_increment.normalize().scale(),
85                    RoundingStrategy::ToZero,
86                ),
87                post_only,
88                time_in_force: Some(time_in_force),
89            },
90            stop: None,
91        };
92
93        let transaction = self
94            .transport
95            .signed_post::<_, (), _>("/orders", None, Some(&data))
96            .await?;
97
98        Ok(transaction)
99    }
100
101    pub async fn limit_sell(
102        &self,
103        pair: MarketPairInfo,
104        size: Decimal,
105        price: Decimal,
106        time_in_force: OrderTimeInForce,
107        post_only: bool,
108    ) -> Result<Order> {
109        let data = OrderRequest {
110            product_id: pair.symbol,
111            client_oid: None,
112            side: OrderSide::Sell,
113            _type: OrderRequestType::Limit {
114                size: size.round_dp(pair.base_increment.normalize().scale()),
115                price: price.round_dp_with_strategy(
116                    pair.quote_increment.normalize().scale(),
117                    RoundingStrategy::AwayFromZero,
118                ),
119                post_only,
120                time_in_force: Some(time_in_force),
121            },
122            stop: None,
123        };
124
125        let transaction = self
126            .transport
127            .signed_post::<_, (), _>("/orders", None, Some(&data))
128            .await?;
129
130        Ok(transaction)
131    }
132
133    pub async fn cancel_order(&self, order_id: String, product_id: Option<&str>) -> Result<String> {
134        let params = if let Some(product_id) = product_id {
135            CancelOrder {
136                product_id: Some(String::from(product_id)),
137            }
138        } else {
139            CancelOrder { product_id: None }
140        };
141
142        let path = format!("/orders/{}", order_id);
143        let resp = self
144            .transport
145            .signed_delete::<_, _, ()>(&path, Some(&params), None)
146            .await?;
147
148        Ok(resp)
149    }
150
151    pub async fn cancel_all_orders<P: Into<MarketPair>>(
152        &self,
153        product_id: Option<P>,
154    ) -> Result<Vec<String>> {
155        let params = if let Some(product_id) = product_id {
156            CancelAllOrders {
157                product_id: Some(product_id.into().0),
158            }
159        } else {
160            CancelAllOrders { product_id: None }
161        };
162
163        let resp = self
164            .transport
165            .signed_delete::<_, _, ()>("/orders", Some(&params), None)
166            .await?;
167
168        Ok(resp)
169    }
170
171    pub async fn get_fills(&self, params: Option<&GetFillsReq>) -> Result<Vec<Fill>> {
172        let resp = self.transport.signed_get::<_, _>("/fills", params).await?;
173
174        Ok(resp)
175    }
176}