Skip to content

Commit e33983f

Browse files
committed
something something working now
1 parent dddbfb6 commit e33983f

File tree

11 files changed

+56
-55
lines changed

11 files changed

+56
-55
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
![Minimum Supported Rust Version](https://img.shields.io/badge/nightly-1.85+-ab6000.svg)
33
[<img alt="crates.io" src="https://img.shields.io/crates/v/v_exchanges.svg?color=fc8d62&logo=rust" height="20" style=flat-square>](https://crates.io/crates/v_exchanges)
44
[<img alt="docs.rs" src="https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs&style=flat-square" height="20">](https://docs.rs/v_exchanges)
5-
![Lines Of Code](https://img.shields.io/badge/LoC-4850-lightblue)
5+
![Lines Of Code](https://img.shields.io/badge/LoC-4848-lightblue)
66
<br>
77
[<img alt="ci errors" src="https://img.shields.io/github/actions/workflow/status/valeratrades/v_exchanges/errors.yml?branch=master&style=for-the-badge&style=flat-square&label=errors&labelColor=420d09" height="20">](https://github.com/valeratrades/v_exchanges/actions?query=branch%3Amaster) <!--NB: Won't find it if repo is private-->
88
[<img alt="ci warnings" src="https://img.shields.io/github/actions/workflow/status/valeratrades/v_exchanges/warnings.yml?branch=master&style=for-the-badge&style=flat-square&label=warnings&labelColor=d16002" height="20">](https://github.com/valeratrades/v_exchanges/actions?query=branch%3Amaster) <!--NB: Won't find it if repo is private-->

examples/binance/market_futures.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ async fn main() {
2323
if let (Ok(key), Ok(secret)) = (env::var("BINANCE_TIGER_READ_KEY"), env::var("BINANCE_TIGER_READ_SECRET")) {
2424
c.auth(key, secret.into());
2525
c.set_recv_window(10000);
26-
let balance_usdt = c.asset_balance("USDT".into(), m).await.unwrap();
26+
let balance_usdt = c.asset_balance("USDT".into(), None, m).await.unwrap();
2727
dbg!(&balance_usdt);
28-
let balances = c.balances(m).await.unwrap();
28+
let balances = c.balances(None, m).await.unwrap();
2929
dbg!(&balances);
3030
} else {
3131
eprintln!("BINANCE_TIGER_READ_KEY or BINANCE_TIGER_READ_SECRET is missing, skipping private API methods.");

examples/bybit/market.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ async fn private(c: &dyn Exchange, m: AbsMarket) {
2727
// .await
2828
// .unwrap();
2929

30-
let balances = c.balances(m).await.unwrap();
30+
let balances = c.balances(None, m).await.unwrap();
3131
dbg!(&balances);
3232

33-
let balance_usdc = c.asset_balance("USDC".into(), c.source_market()).await.unwrap();
33+
let balance_usdc = c.asset_balance("USDC".into(), Some(5000), c.source_market()).await.unwrap();
3434
dbg!(&balance_usdc);
3535
}
3636

examples/mexc.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ async fn main() {
1313
let price = c.price(("BTC", "USDT").into(), m).await.unwrap();
1414
dbg!(&price);
1515

16-
let balances = c.balances(m).await.unwrap();
16+
let balances = c.balances(None, m).await.unwrap();
1717
dbg!(&balances);
1818
}
1919

v_exchanges/src/binance/futures/account.rs

Lines changed: 12 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,13 @@ use crate::core::{AssetBalance, Balances};
1313

1414
// balance {{{
1515
//DUP: difficult to escape duplicating half the [balances] method due to a) not requiring usd value b) binance not having individual asset balance endpoint
16-
pub async fn asset_balance(client: &v_exchanges_adapters::Client, asset: Asset) -> Result<AssetBalance> {
16+
pub async fn asset_balance(client: &v_exchanges_adapters::Client, asset: Asset, recv_window: Option<u16>) -> Result<AssetBalance> {
1717
assert!(client.is_authenticated::<BinanceOption>());
18-
let r: Vec<AssetBalanceResponse> = client
19-
.get_no_query("/fapi/v3/balance", [
20-
BinanceOption::HttpUrl(BinanceHttpUrl::FuturesUsdM),
21-
BinanceOption::HttpAuth(BinanceAuth::Sign),
22-
])
23-
.await
24-
.unwrap();
18+
let mut options = vec![BinanceOption::HttpUrl(BinanceHttpUrl::FuturesUsdM), BinanceOption::HttpAuth(BinanceAuth::Sign)];
19+
if let Some(rw) = recv_window {
20+
options.push(BinanceOption::RecvWindow(rw));
21+
}
22+
let r: Vec<AssetBalanceResponse> = client.get_no_query("/fapi/v3/balance", options).await.unwrap();
2523
let vec_balance: Vec<AssetBalance> = r
2624
.into_iter()
2725
.map(|r| AssetBalance {
@@ -34,15 +32,13 @@ pub async fn asset_balance(client: &v_exchanges_adapters::Client, asset: Asset)
3432
Ok(balance)
3533
}
3634

37-
pub async fn balances(client: &v_exchanges_adapters::Client, prices: &BTreeMap<Pair, f64>) -> Result<Balances> {
35+
pub async fn balances(client: &v_exchanges_adapters::Client, recv_window: Option<u16>, prices: &BTreeMap<Pair, f64>) -> Result<Balances> {
3836
assert!(client.is_authenticated::<BinanceOption>());
39-
let rs: Vec<AssetBalanceResponse> = client
40-
.get_no_query("/fapi/v3/balance", [
41-
BinanceOption::HttpUrl(BinanceHttpUrl::FuturesUsdM),
42-
BinanceOption::HttpAuth(BinanceAuth::Sign),
43-
])
44-
.await
45-
.unwrap();
37+
let mut options = vec![BinanceOption::HttpUrl(BinanceHttpUrl::FuturesUsdM), BinanceOption::HttpAuth(BinanceAuth::Sign)];
38+
if let Some(rw) = recv_window {
39+
options.push(BinanceOption::RecvWindow(rw));
40+
}
41+
let rs: Vec<AssetBalanceResponse> = client.get_no_query("/fapi/v3/balance", options).await.unwrap();
4642

4743
fn usd_value(underlying: f64, asset: Asset, prices: &BTreeMap<Pair, f64>) -> Result<Usd> {
4844
if underlying == 0. {

v_exchanges/src/binance/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -83,22 +83,22 @@ impl Exchange for Binance {
8383
}
8484
}
8585

86-
async fn asset_balance(&self, asset: Asset, am: AbsMarket) -> Result<AssetBalance> {
86+
async fn asset_balance(&self, asset: Asset, recv_window: Option<u16>, am: AbsMarket) -> Result<AssetBalance> {
8787
match am {
8888
AbsMarket::Binance(m) => match m {
89-
Market::Futures => futures::account::asset_balance(self, asset).await,
89+
Market::Futures => futures::account::asset_balance(self, asset, recv_window).await,
9090
_ => unimplemented!(),
9191
},
9292
_ => Err(WrongExchangeError::new(self.exchange_name(), am).into()),
9393
}
9494
}
9595

96-
async fn balances(&self, am: AbsMarket) -> Result<Balances> {
96+
async fn balances(&self, recv_window: Option<u16>, am: AbsMarket) -> Result<Balances> {
9797
match am {
9898
AbsMarket::Binance(m) => match m {
9999
Market::Futures => {
100100
let prices = self.prices(None, am).await?;
101-
futures::account::balances(&self.client, &prices).await
101+
futures::account::balances(&self.client, recv_window, &prices).await
102102
}
103103
_ => unimplemented!(),
104104
},

v_exchanges/src/bybit/account.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,20 +8,22 @@ use v_utils::{macros::ScreamIt, trades::Asset};
88

99
use crate::core::{AssetBalance, Balances};
1010

11-
pub async fn asset_balance(client: &v_exchanges_adapters::Client, asset: Asset) -> Result<AssetBalance> {
11+
pub async fn asset_balance(client: &v_exchanges_adapters::Client, asset: Asset, recv_window: Option<u16>) -> Result<AssetBalance> {
1212
assert!(client.is_authenticated::<BybitOption>());
13-
let balances: Balances = balances(client).await?;
13+
let balances: Balances = balances(client, recv_window).await?;
1414
let balance: &AssetBalance = balances.iter().find(|b| b.asset == asset).ok_or_else(|| eyre!("No balance found for asset: {:?}", asset))?;
1515
Ok(*balance)
1616
}
1717

1818
/// Should be calling https://bybit-exchange.github.io/docs/v5/asset/balance/all-balance, but with how I'm registered on bybit, my key doesn't have permissions for that (they require it to be able to `transfer` for some reason)
19-
pub async fn balances(client: &Client) -> Result<Balances> {
19+
pub async fn balances(client: &Client, recv_window: Option<u16>) -> Result<Balances> {
2020
assert!(client.is_authenticated::<BybitOption>());
2121

22-
let value: serde_json::Value = client
23-
.get("/v5/account/wallet-balance", &[("accountType", "UNIFIED")], [BybitOption::HttpAuth(BybitHttpAuth::V3AndAbove)])
24-
.await?;
22+
let mut options = vec![BybitOption::HttpAuth(BybitHttpAuth::V3AndAbove)];
23+
if let Some(rw) = recv_window {
24+
options.push(BybitOption::RecvWindow(rw));
25+
}
26+
let value: serde_json::Value = client.get("/v5/account/wallet-balance", &[("accountType", "UNIFIED")], options).await?;
2527

2628
let account_response: AccountResponse = serde_json::from_value(value)?;
2729
assert_eq!(account_response.result.list.len(), 1);

v_exchanges/src/bybit/mod.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -84,20 +84,20 @@ impl Exchange for Bybit {
8484
}
8585
}
8686

87-
async fn asset_balance(&self, asset: Asset, am: AbsMarket) -> Result<AssetBalance> {
87+
async fn asset_balance(&self, asset: Asset, recv_window: Option<u16>, am: AbsMarket) -> Result<AssetBalance> {
8888
match am {
8989
AbsMarket::Bybit(m) => match m {
90-
Market::Linear => account::asset_balance(&self.client, asset).await,
90+
Market::Linear => account::asset_balance(&self.client, asset, recv_window).await,
9191
_ => unimplemented!(),
9292
},
9393
_ => Err(WrongExchangeError::new(self.exchange_name(), am).into()),
9494
}
9595
}
9696

97-
async fn balances(&self, am: AbsMarket) -> Result<Balances> {
97+
async fn balances(&self, recv_window: Option<u16>, am: AbsMarket) -> Result<Balances> {
9898
match am {
9999
AbsMarket::Bybit(m) => match m {
100-
Market::Linear => account::balances(&self.client).await,
100+
Market::Linear => account::balances(&self.client, recv_window).await,
101101
_ => unimplemented!(),
102102
},
103103
_ => Err(WrongExchangeError::new(self.exchange_name(), am).into()),

v_exchanges/src/core.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ use v_utils::{
1111
utils::filter_nulls,
1212
};
1313

14+
/// Main trait for all standardized exchange interactions
15+
/// # Other
16+
/// - each private method provides recv_window
1417
#[async_trait::async_trait]
1518
pub trait Exchange: std::fmt::Debug + Send {
1619
// dev {{{
@@ -27,6 +30,7 @@ pub trait Exchange: std::fmt::Debug + Send {
2730
fn auth(&mut self, key: String, secret: SecretString);
2831
/// Set number of **milliseconds** the request is valid for. Recv Window of over a minute does not make sense, thus it's expressed as u16.
2932
//Q: really don't think this should be used like that, globally, - if unable to find cases, rm in a month (now is 2025/01/24)
33+
#[deprecated(note = "This shouldn't be a global setting, but a per-request one. Use `recv_window` in the request instead.")]
3034
fn set_recv_window(&mut self, recv_window: u16);
3135
fn set_timeout(&mut self, timeout: std::time::Duration) {
3236
self.__client_mut().client.config.timeout = timeout;
@@ -53,9 +57,9 @@ pub trait Exchange: std::fmt::Debug + Send {
5357
//TODO!!!: async fn spawn_klines_listener(&self, symbol: Pair, tf: Timeframe) -> mpsc::Receiver<Kline>;
5458

5559
/// balance of a specific asset. Does not guarantee provision of USD values.
56-
async fn asset_balance(&self, asset: Asset, m: AbsMarket) -> Result<AssetBalance>;
60+
async fn asset_balance(&self, asset: Asset, recv_window: Option<u16>, m: AbsMarket) -> Result<AssetBalance>;
5761
/// vec of _non-zero_ balances exclusively. Provides USD values.
58-
async fn balances(&self, m: AbsMarket) -> Result<Balances>;
62+
async fn balances(&self, recv_window: Option<u16>, m: AbsMarket) -> Result<Balances>;
5963
//? potentially `total_balance`? Would return precompiled USDT-denominated balance of a (bybit::wallet/binance::account)
6064
// balances are defined for each margin type: [futures_balance, spot_balance, margin_balance], but note that on some exchanges, (like bybit), some of these may point to the same exact call
6165
// to negate confusion could add a `total_balance` endpoint

v_exchanges/src/mexc/account.rs

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,25 @@ use v_utils::prelude::*;
66

77
use crate::{AssetBalance, Balances};
88

9-
pub async fn asset_balance(client: &Client, asset: Asset) -> Result<AssetBalance> {
9+
pub async fn asset_balance(client: &Client, asset: Asset, recv_window: Option<u16>) -> Result<AssetBalance> {
1010
assert!(client.is_authenticated::<MexcOption>());
11+
let mut options = vec![MexcOption::HttpUrl(MexcHttpUrl::Futures), MexcOption::HttpAuth(MexcAuth::Sign)];
12+
if let Some(rw) = recv_window {
13+
options.push(MexcOption::RecvWindow(rw));
14+
}
1115
let endpoint = format!("/api/v1/private/account/asset/{}", asset);
12-
let r: AssetBalanceResponse = client
13-
.get_no_query(&endpoint, [MexcOption::HttpUrl(MexcHttpUrl::Futures), MexcOption::HttpAuth(MexcAuth::Sign)])
14-
.await
15-
.unwrap();
16+
let r: AssetBalanceResponse = client.get_no_query(&endpoint, options).await.unwrap();
1617

1718
Ok(r.data.into())
1819
}
1920

20-
pub async fn balances(client: &Client) -> Result<Balances> {
21+
pub async fn balances(client: &Client, recv_window: Option<u16>) -> Result<Balances> {
2122
assert!(client.is_authenticated::<MexcOption>());
22-
let rs: BalancesResponse = client
23-
.get_no_query("/api/v1/private/account/assets", [
24-
MexcOption::HttpUrl(MexcHttpUrl::Futures),
25-
MexcOption::HttpAuth(MexcAuth::Sign),
26-
])
27-
.await
28-
.unwrap();
23+
let mut options = vec![MexcOption::HttpUrl(MexcHttpUrl::Futures), MexcOption::HttpAuth(MexcAuth::Sign)];
24+
if let Some(rw) = recv_window {
25+
options.push(MexcOption::RecvWindow(rw));
26+
}
27+
let rs: BalancesResponse = client.get_no_query("/api/v1/private/account/assets", options).await.unwrap();
2928

3029
let non_zero: Vec<AssetBalance> = rs.data.into_iter().filter(|r| r.equity != 0.).map(|r| r.into()).collect();
3130
// dance with tambourine to request for usdt prices of all assets except usdt itself

0 commit comments

Comments
 (0)