Skip to content

Commit dd3fa4b

Browse files
committed
_
1 parent 2bea0d5 commit dd3fa4b

File tree

6 files changed

+116
-63
lines changed

6 files changed

+116
-63
lines changed

examples/binance/market.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,13 @@ async fn main() {
1212

1313
b.update_default_option(BinanceOption::HttpUrl(BinanceHttpUrl::FuturesUsdM));
1414

15-
//before implementing the trait for bybit too, was able to just do eg: `let klines = client.futures_klines(("BTC", "USDT").into(), "1m".into(), 2, None, None).await.unwrap();`
16-
1715
let klines = b.futures_klines(("BTC", "USDT").into(), "1m".into(), 2, None, None).await.unwrap();
1816
let price = b.futures_price(("BTC", "USDT").into()).await.unwrap();
1917
dbg!(&klines, price);
2018

19+
let trades: serde_json::Value = b.get("/fapi/v1/aggTrades", &[("symbol", "BTCUSDT"), ("limit", "2")], [BinanceOption::Default]).await.unwrap();
20+
dbg!(&trades);
21+
2122
if let (Ok(key), Ok(secret)) = (env::var("BINANCE_TIGER_READ_KEY"), env::var("BINANCE_TIGER_READ_SECRET")) {
2223
b.update_default_option(BinanceOption::Key(key));
2324
b.update_default_option(BinanceOption::Secret(secret));

examples/bybit/market.rs

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -10,39 +10,20 @@ async fn main() {
1010

1111
let mut bb = Bybit::default();
1212

13-
let ticker: serde_json::Value =
14-
bb.0.get("/v5/market/tickers", &[("category", "spot"), ("symbol", "BTCUSDT")], [BybitOption::Default])
15-
.await
16-
.expect("failed to get ticker");
17-
println!("Ticker:\n{ticker}");
18-
1913
if let (Ok(key), Ok(secret)) = (env::var("BYBIT_TIGER_READ_KEY"), env::var("BYBIT_TIGER_READ_SECRET")) {
20-
bb.0.update_default_option(BybitOption::Key(key));
21-
bb.0.update_default_option(BybitOption::Secret(secret));
14+
bb.update_default_option(BybitOption::Key(key));
15+
bb.update_default_option(BybitOption::Secret(secret));
2216
private(&mut bb).await;
2317
} else {
2418
eprintln!("BYBIT_TIGER_READ_KEY or BYBIT_TIGER_READ_SECRET is missing, skipping private API methods.");
2519
}
26-
27-
//client.update_default_option(BinanceOption::HttpUrl(BinanceHttpUrl::FuturesUsdM));
28-
//let klines = client.futures_klines(("BTC", "USDT").into(), "1m".into(), 2, None, None).await.unwrap();
29-
//let price = client.futures_price(("BTC", "USDT").into()).await.unwrap();
30-
//dbg!(&klines, price);
31-
//
32-
//if let (Ok(key), Ok(secret)) = (env::var("BINANCE_TIGER_READ_KEY"), env::var("BINANCE_TIGER_READ_SECRET")) {
33-
// client.update_default_option(BinanceOption::Key(key));
34-
// client.update_default_option(BinanceOption::Secret(secret));
35-
// let balance = client.futures_asset_balance("USDT".into()).await.unwrap();
36-
// dbg!(&balance);
37-
//} else {
38-
// eprintln!("BINANCE_TIGER_READ_KEY or BINANCE_TIGER_READ_SECRET is missing, skipping private API methods.");
39-
//}
4020
}
4121

4222
async fn private(bb: &mut Bybit) {
43-
let balance: serde_json::Value = bb
44-
.get("/v5/account/wallet-balance", &[("accountType", "UNIFIED")], [BybitOption::HttpAuth(BybitHttpAuth::V3AndAbove)])
45-
.await
46-
.expect("failed to get balance");
47-
println!("Balance:\n{balance}");
23+
//let key_permissions: serde_json::Value = bb.get_no_query("/v5/user/query-api", [BybitOption::HttpAuth(BybitHttpAuth::V3AndAbove)])
24+
// .await
25+
// .unwrap();
26+
27+
let balances = bb.futures_balances().await.unwrap();
28+
dbg!(&balances);
4829
}

v_exchanges/src/binance/futures/account.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ impl From<AssetBalanceResponse> for AssetBalance {
5151
Self {
5252
asset: r.asset.into(),
5353
balance: r.balance,
54-
timestamp: r.update_time,
54+
timestamp: r.update_time as i64,
5555
}
5656
}
5757
}

v_exchanges/src/bybit/account.rs

Lines changed: 97 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,120 @@
11
use std::str::FromStr;
2+
use v_utils::macros::ScreamIt;
23

34
use color_eyre::eyre::Result;
45
use serde::{Deserialize, Serialize};
6+
use serde_json::Value;
7+
use v_exchanges_adapters::bybit::{BybitHttpAuth, BybitOption};
8+
use serde_with::{serde_as, DisplayFromStr};
59

610
use crate::core::AssetBalance;
11+
use v_utils::trades::Asset;
712

13+
pub async fn asset_balance(client: &v_exchanges_adapters::Client, asset: Asset) -> Result<AssetBalance> {
14+
let balances = balances(client).await?;
15+
let balance = balances.into_iter().find(|b| b.asset == asset).unwrap();
16+
Ok(balance)
17+
}
18+
19+
/// 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)
820
pub async fn balances(client: &v_exchanges_adapters::Client) -> Result<Vec<AssetBalance>> {
9-
println!("bybit::account::balances");
10-
todo!();
21+
let value: serde_json::Value = client
22+
.get("/v5/account/wallet-balance", &[("accountType", "UNIFIED")], [BybitOption::HttpAuth(BybitHttpAuth::V3AndAbove)])
23+
.await?;
24+
25+
let account_response: AccountResponse = serde_json::from_value(value)?;
26+
assert_eq!(account_response.result.list.len(), 1);
27+
let account_info = account_response.result.list.first().unwrap();
28+
29+
let mut balances = Vec::new();
30+
for r in &account_info.coin {
31+
balances.push(
32+
AssetBalance {
33+
asset: (&*r.coin).into(),
34+
balance: r.wallet_balance,
35+
timestamp: account_response.time,
36+
}
37+
);
38+
}
39+
Ok(balances)
1140
}
1241

13-
#[derive(Serialize, Deserialize)]
14-
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
42+
43+
#[derive(Debug, Clone, ScreamIt, Copy)]
1544
pub enum AccountType {
1645
Spot,
1746
Contract,
1847
Unified,
1948
Funding,
2049
Option,
2150
}
22-
impl std::fmt::Display for AccountType {
23-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24-
let s = serde_plain::to_string(self).map_err(|_| std::fmt::Error)?;
25-
write!(f, "{s}")
26-
}
27-
}
28-
impl FromStr for AccountType {
29-
type Err = ();
3051

31-
fn from_str(s: &str) -> Result<Self, Self::Err> {
32-
serde_plain::from_str(s).map_err(|_| ())
33-
}
52+
#[derive(Debug, Serialize, Deserialize)]
53+
#[serde(rename_all = "camelCase")]
54+
pub struct AccountResponse {
55+
pub result: AccountResult,
56+
pub ret_code: i64,
57+
pub ret_ext_info: RetExtInfo,
58+
pub ret_msg: String,
59+
pub time: i64,
3460
}
3561

36-
mod tests {
37-
use insta;
62+
#[derive(Debug, Serialize, Deserialize)]
63+
pub struct AccountResult {
64+
pub list: Vec<AccountInfo>,
65+
}
3866

39-
use super::*;
67+
#[derive(Debug, Serialize, Deserialize)]
68+
#[serde(rename_all = "camelCase")]
69+
pub struct AccountInfo {
70+
#[serde(rename = "accountIMRate")]
71+
pub account_im_rate: Option<Value>,
72+
#[serde(rename = "accountLTV")]
73+
pub account_ltv: Option<Value>,
74+
#[serde(rename = "accountMMRate")]
75+
pub account_mm_rate: Option<Value>,
76+
pub account_type: AccountType,
77+
pub coin: Vec<CoinInfo>,
78+
pub total_available_balance: String,
79+
pub total_equity: String,
80+
pub total_initial_margin: String,
81+
pub total_maintenance_margin: String,
82+
pub total_margin_balance: String,
83+
#[serde(rename = "totalPerpUPL")]
84+
pub total_perp_upl: String,
85+
pub total_wallet_balance: String,
86+
}
4087

41-
#[test]
42-
fn test_account_type_serde() {
43-
insta::assert_debug_snapshot!(format!("{}", AccountType::Unified), @r#""UNIFIED""#);
44-
let s = "UNIFIED";
45-
let _: AccountType = s.parse().unwrap();
46-
}
88+
#[serde_as]
89+
#[derive(Debug, Serialize, Deserialize)]
90+
#[serde(rename_all = "camelCase")]
91+
pub struct CoinInfo {
92+
pub accrued_interest: String,
93+
/// deprecated
94+
pub available_to_borrow: Option<Value>, //? can I start it with __, will serde understand?
95+
pub available_to_withdraw: String,
96+
pub bonus: String,
97+
pub borrow_amount: String,
98+
pub coin: String,
99+
pub collateral_switch: bool,
100+
pub cum_realised_pnl: String,
101+
pub equity: String,
102+
pub locked: String,
103+
pub margin_collateral: bool,
104+
pub spot_hedging_qty: String,
105+
#[serde(rename = "totalOrderIM")]
106+
pub total_order_im: String,
107+
#[serde(rename = "totalPositionIM")]
108+
pub total_position_im: String,
109+
#[serde(rename = "totalPositionMM")]
110+
pub total_position_mm: String,
111+
#[serde_as(as = "DisplayFromStr")]
112+
pub unrealised_pnl: f64,
113+
#[serde_as(as = "DisplayFromStr")]
114+
pub usd_value: f64,
115+
#[serde_as(as = "DisplayFromStr")]
116+
pub wallet_balance: f64,
47117
}
118+
119+
#[derive(Debug, Serialize, Deserialize)]
120+
pub struct RetExtInfo {}

v_exchanges/src/bybit/mod.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,11 @@ pub mod account;
33
use color_eyre::eyre::Result;
44
use derive_more::derive::{Deref, DerefMut};
55
use v_exchanges_adapters::{Client, bybit};
6-
use v_utils::{
7-
macros::WrapNew,
8-
trades::{Asset, Pair, Timeframe},
9-
};
6+
use v_utils::trades::{Asset, Pair, Timeframe};
107

118
use crate::core::{AssetBalance, Exchange, Klines};
129

13-
#[derive(Clone, Debug, Default, Deref)]
10+
#[derive(Clone, Debug, Default, Deref, DerefMut)]
1411
pub struct Bybit(pub Client);
1512

1613
//? currently client ends up importing this from crate::binance, but could it be possible to lift the [Client] reexport up, and still have the ability to call all exchange methods right on it?
@@ -26,8 +23,7 @@ impl Exchange for Bybit {
2623
}
2724

2825
async fn futures_asset_balance(&self, asset: Asset) -> Result<AssetBalance> {
29-
//futures::account::asset_balance(&self.0, asset).await
30-
todo!();
26+
account::asset_balance(&self.0, asset).await
3127
}
3228

3329
async fn futures_balances(&self) -> Result<Vec<AssetBalance>> {

v_exchanges/src/core.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@ pub trait Exchange {
1212
// Defined in terms of actors
1313
//TODO!!!: fn spawn_klines_listener(&self, symbol: Pair, tf: Timeframe) -> mpsc::Receiver<Kline>;
1414

15-
//DO: balances
15+
/// balance of a specific asset
1616
fn futures_asset_balance(&self, asset: Asset) -> impl std::future::Future<Output = Result<AssetBalance>> + Send;
17+
/// vec of balances of specific assets
1718
fn futures_balances(&self) -> impl std::future::Future<Output = Result<Vec<AssetBalance>>> + Send;
19+
//? potentially `total_balance`? Would return precompiled USDT-denominated balance of a (bybit::wallet/binance::account)
1820
// 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
1921
// to negate confusion could add a `total_balance` endpoint
2022

@@ -47,5 +49,5 @@ pub struct AssetBalance {
4749
//available_balance: f64,
4850
//max_withdraw_amount: f64,
4951
//margin_available: bool,
50-
pub timestamp: u64,
52+
pub timestamp: i64,
5153
}

0 commit comments

Comments
 (0)