Skip to content

Commit daf4c9a

Browse files
authored
Merge pull request #17 from valeratrades/market_param
market_param
2 parents 945da81 + ff01d8e commit daf4c9a

File tree

7 files changed

+163
-101
lines changed

7 files changed

+163
-101
lines changed

examples/binance/market_futures.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
use std::env;
22

3-
use v_exchanges::{binance::Binance, core::Exchange};
3+
use v_exchanges::{
4+
binance::{self},
5+
core::{Exchange, MarketTrait as _},
6+
};
47

58
#[tokio::main]
69
async fn main() {
710
color_eyre::install().unwrap();
811
v_utils::utils::init_subscriber(v_utils::utils::LogDestination::xdg("v_exchanges"));
912

10-
let mut bn = Binance::default();
13+
let m = binance::Market::Futures;
14+
let mut bn = m.client();
1115

12-
let klines = bn.futures_klines(("BTC", "USDT").into(), "1m".into(), 2.into()).await.unwrap();
13-
let price = bn.futures_price(("BTC", "USDT").into()).await.unwrap();
16+
let klines = bn.klines(("BTC", "USDT").into(), "1m".into(), 2.into(), m).await.unwrap();
17+
let price = bn.price(("BTC", "USDT").into(), m).await.unwrap();
1418
dbg!(&klines, price);
1519

1620
if let (Ok(key), Ok(secret)) = (env::var("BINANCE_TIGER_READ_KEY"), env::var("BINANCE_TIGER_READ_SECRET")) {
1721
bn.auth(key, secret);
18-
let balance = bn.futures_asset_balance("USDT".into()).await.unwrap();
22+
let balance = bn.asset_balance("USDT".into(), m).await.unwrap();
1923
dbg!(&balance);
2024
} else {
2125
eprintln!("BINANCE_TIGER_READ_KEY or BINANCE_TIGER_READ_SECRET is missing, skipping private API methods.");

examples/binance/market_spot.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
use v_exchanges::{binance::Binance, core::Exchange};
1+
use v_exchanges::{
2+
binance::{self},
3+
core::{Exchange, MarketTrait as _},
4+
};
25

36
#[tokio::main]
47
async fn main() {
58
color_eyre::install().unwrap();
69
v_utils::utils::init_subscriber(v_utils::utils::LogDestination::xdg("v_exchanges"));
7-
let bn = Binance::default();
810

9-
let spot_klines = bn.spot_klines(("BTC", "USDT").into(), "1m".into(), 2.into()).await.unwrap();
11+
let m = binance::Market::Spot;
12+
let bn = m.client();
13+
14+
let spot_klines = bn.klines(("BTC", "USDT").into(), "1m".into(), 2.into(), m).await.unwrap();
1015
dbg!(&spot_klines);
1116

12-
let spot_prices = bn.spot_prices(None).await.unwrap();
17+
let spot_prices = bn.prices(None, m).await.unwrap();
1318
dbg!(&spot_prices[..5]);
1419
}

examples/bybit/market.rs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
use std::env;
22

3-
use v_exchanges::{bybit::Bybit, core::Exchange};
3+
use v_exchanges::{bybit::{self, Bybit}, core::{Exchange, MarketTrait as _}};
44

55
#[tokio::main]
66
async fn main() {
77
color_eyre::install().unwrap();
88
v_utils::utils::init_subscriber(v_utils::utils::LogDestination::xdg("v_exchanges"));
99

10-
let mut bb = Bybit::default();
10+
//let m: Market = "Bybit/Linear".into(); // would be nice to be able to do it like this
11+
let m = bybit::Market::Linear;
12+
let mut bb = m.client();
1113

1214
//let ticker: serde_json::Value =
1315
//bb.get("/v5/market/tickers", &[("category", "spot"), ("symbol", "BTCUSDT")], [BybitOption::Default])
@@ -17,22 +19,22 @@ async fn main() {
1719

1820
//let klines = bb.futures_klines(("BTC", "USDT").into(), "1m".into(), 2.into()).await.unwrap();
1921
//dbg!(&klines);
20-
let price = bb.futures_price(("BTC", "USDT").into()).await.unwrap();
22+
let price = bb.price(("BTC", "USDT").into(), m).await.unwrap();
2123
dbg!(&price);
2224

2325
if let (Ok(key), Ok(secret)) = (env::var("BYBIT_TIGER_READ_KEY"), env::var("BYBIT_TIGER_READ_SECRET")) {
2426
bb.auth(key, secret);
25-
private(&mut bb).await;
27+
private(&mut bb, m).await;
2628
} else {
2729
eprintln!("BYBIT_TIGER_READ_KEY or BYBIT_TIGER_READ_SECRET is missing, skipping private API methods.");
2830
}
2931
}
3032

31-
async fn private(bb: &mut Bybit) {
33+
async fn private(bb: &mut Bybit, m: bybit::Market) {
3234
//let key_permissions: serde_json::Value = bb.get_no_query("/v5/user/query-api", [BybitOption::HttpAuth(BybitHttpAuth::V3AndAbove)])
3335
// .await
3436
// .unwrap();
3537

36-
let balances = bb.futures_balances().await.unwrap();
38+
let balances = bb.balances(m).await.unwrap();
3739
dbg!(&balances);
3840
}

v_exchanges/src/binance/mod.rs

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,44 @@ pub struct Binance(pub Client);
1515

1616
//? 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?
1717
impl Exchange for Binance {
18+
type M = Market;
19+
1820
fn auth<S: Into<String>>(&mut self, key: S, secret: S) {
1921
self.update_default_option(BinanceOption::Key(key.into()));
2022
self.update_default_option(BinanceOption::Secret(secret.into()));
2123
}
2224

23-
async fn spot_klines(&self, pair: Pair, tf: Timeframe, range: KlinesRequestRange) -> Result<Klines> {
24-
market::klines(&self.0, pair, tf, range, Market::Spot).await
25-
}
26-
27-
async fn spot_prices(&self, pairs: Option<Vec<Pair>>) -> Result<Vec<(Pair, f64)>> {
28-
spot::market::prices(&self.0, pairs).await
25+
async fn klines(&self, pair: Pair, tf: Timeframe, range: KlinesRequestRange, m: Self::M) -> Result<Klines> {
26+
market::klines(&self.0, pair, tf, range, m).await
2927
}
3028

31-
async fn spot_price(&self, pair: Pair) -> Result<f64> {
32-
spot::market::price(&self.0, pair).await
29+
async fn prices(&self, pairs: Option<Vec<Pair>>, m: Self::M) -> Result<Vec<(Pair, f64)>> {
30+
match m {
31+
Market::Spot => spot::market::prices(&self.0, pairs).await,
32+
_ => unimplemented!(),
33+
}
3334
}
3435

35-
async fn futures_klines(&self, pair: Pair, tf: Timeframe, range: KlinesRequestRange) -> Result<Klines> {
36-
market::klines(&self.0, pair, tf, range, Market::Futures).await
36+
async fn price(&self, pair: Pair, m: Self::M) -> Result<f64> {
37+
match m {
38+
Market::Spot => spot::market::price(&self.0, pair).await,
39+
Market::Futures => futures::market::price(&self.0, pair).await,
40+
_ => unimplemented!(),
41+
}
3742
}
3843

39-
async fn futures_price(&self, pair: Pair) -> Result<f64> {
40-
futures::market::price(&self.0, pair).await
44+
async fn asset_balance(&self, asset: Asset, m: Self::M) -> Result<AssetBalance> {
45+
match m {
46+
Market::Futures => futures::account::asset_balance(self, asset).await,
47+
_ => unimplemented!(),
48+
}
4149
}
4250

43-
async fn futures_asset_balance(&self, asset: Asset) -> Result<AssetBalance> {
44-
futures::account::asset_balance(&self.0, asset).await
45-
}
46-
47-
async fn futures_balances(&self) -> Result<Vec<AssetBalance>> {
48-
futures::account::balances(&self.0).await
51+
async fn balances(&self, m: Self::M) -> Result<Vec<AssetBalance>> {
52+
match m {
53+
Market::Futures => futures::account::balances(&self.0).await,
54+
_ => unimplemented!(),
55+
}
4956
}
5057
}
5158

@@ -56,3 +63,9 @@ pub enum Market {
5663
Spot,
5764
Margin,
5865
}
66+
impl crate::core::MarketTrait for Market {
67+
type Client = Binance;
68+
fn client(&self) -> Binance {
69+
Binance::default()
70+
}
71+
}

v_exchanges/src/bybit/mod.rs

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,40 +15,44 @@ pub struct Bybit(pub Client);
1515

1616
//? 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?
1717
impl Exchange for Bybit {
18+
type M = Market;
19+
1820
fn auth<S: Into<String>>(&mut self, key: S, secret: S) {
1921
self.update_default_option(BybitOption::Key(key.into()));
2022
self.update_default_option(BybitOption::Secret(secret.into()));
2123
}
2224

23-
async fn spot_klines(&self, pair: Pair, tf: Timeframe, range: KlinesRequestRange) -> Result<Klines> {
24-
todo!();
25+
async fn klines(&self, pair: Pair, tf: Timeframe, range: KlinesRequestRange, m: Self::M) -> Result<Klines> {
26+
match m {
27+
Market::Linear => market::klines(&self.0, pair, tf, range).await,
28+
_ => unimplemented!(),
29+
}
2530
}
2631

27-
async fn spot_prices(&self, pairs: Option<Vec<Pair>>) -> Result<Vec<(Pair, f64)>> {
28-
todo!();
32+
async fn price(&self, pair: Pair, m: Self::M) -> Result<f64> {
33+
match m {
34+
Market::Linear => market::price(&self.0, pair).await,
35+
_ => unimplemented!(),
36+
}
2937
}
3038

31-
async fn spot_price(&self, symbol: Pair) -> Result<f64> {
39+
async fn prices(&self, pairs: Option<Vec<Pair>>, m: Self::M) -> Result<Vec<(Pair, f64)>> {
3240
todo!();
3341
}
3442

35-
async fn futures_klines(&self, symbol: Pair, tf: Timeframe, range: KlinesRequestRange) -> Result<Klines> {
36-
market::klines(&self.0, symbol, tf, range).await
37-
}
38-
39-
async fn futures_price(&self, symbol: Pair) -> Result<f64> {
40-
market::price(&self.0, symbol).await
43+
async fn asset_balance(&self, asset: Asset, m: Self::M) -> Result<AssetBalance> {
44+
match m {
45+
Market::Linear => account::asset_balance(&self.0, asset).await,
46+
_ => unimplemented!(),
47+
}
4148
}
4249

43-
async fn futures_asset_balance(&self, asset: Asset) -> Result<AssetBalance> {
44-
account::asset_balance(&self.0, asset).await
50+
async fn balances(&self, m: Self::M) -> Result<Vec<AssetBalance>> {
51+
match m{
52+
Market::Linear => account::balances(&self.0).await,
53+
_ => unimplemented!(),
54+
}
4555
}
46-
47-
async fn futures_balances(&self) -> Result<Vec<AssetBalance>> {
48-
account::balances(&self.0).await
49-
}
50-
51-
//DO: async fn balance(&self,
5256
}
5357

5458

@@ -59,3 +63,9 @@ pub enum Market {
5963
Spot,
6064
Inverse,
6165
}
66+
impl crate::core::MarketTrait for Market {
67+
type Client = Bybit;
68+
fn client(&self) -> Bybit {
69+
Bybit::default()
70+
}
71+
}

v_exchanges/src/core.rs

Lines changed: 76 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,24 @@ use v_utils::trades::{Asset, Kline, Pair, Timeframe};
88
//TODO!!!!!!!!!!!!!: klines switch to defining the range via an Enum over either limit either start and end times
99

1010
pub trait Exchange {
11-
fn auth<S: Into<String>>(&mut self, key: S, secret: S);
11+
type M: MarketTrait;
1212

13-
fn spot_klines(&self, pair: Pair, tf: Timeframe, range: KlinesRequestRange) -> impl std::future::Future<Output = Result<Klines>> + Send;
14-
fn spot_price(&self, pair: Pair) -> impl std::future::Future<Output = Result<f64>> + Send;
15-
/// If no symbols are specified, returns all spot prices.
16-
fn spot_prices(&self, pairs: Option<Vec<Pair>>) -> impl std::future::Future<Output = Result<Vec<(Pair, f64)>>> + Send;
13+
fn auth<S: Into<String>>(&mut self, key: S, secret: S);
1714

1815
//? should I have Self::Pair too? Like to catch the non-existent ones immediately? Although this would increase the error surface on new listings.
19-
fn futures_klines(&self, pair: Pair, tf: Timeframe, range: KlinesRequestRange) -> impl std::future::Future<Output = Result<Klines>> + Send;
20-
fn futures_price(&self, pair: Pair) -> impl std::future::Future<Output = Result<f64>> + Send;
16+
fn klines(&self, pair: Pair, tf: Timeframe, range: KlinesRequestRange, m: Self::M) -> impl std::future::Future<Output = Result<Klines>> + Send;
17+
18+
/// If no pairs are specified, returns for all;
19+
fn prices(&self, pairs: Option<Vec<Pair>>, m: Self::M) -> impl std::future::Future<Output = Result<Vec<(Pair, f64)>>> + Send;
20+
fn price(&self, pair: Pair, m: Self::M) -> impl std::future::Future<Output = Result<f64>> + Send;
2121

2222
// Defined in terms of actors
2323
//TODO!!!: fn spawn_klines_listener(&self, symbol: Pair, tf: Timeframe) -> mpsc::Receiver<Kline>;
2424

2525
/// balance of a specific asset
26-
fn futures_asset_balance(&self, asset: Asset) -> impl std::future::Future<Output = Result<AssetBalance>> + Send;
26+
fn asset_balance(&self, asset: Asset, m: Self::M) -> impl std::future::Future<Output = Result<AssetBalance>> + Send;
2727
/// vec of balances of specific assets
28-
fn futures_balances(&self) -> impl std::future::Future<Output = Result<Vec<AssetBalance>>> + Send;
28+
fn balances(&self, m: Self::M) -> impl std::future::Future<Output = Result<Vec<AssetBalance>>> + Send;
2929
//? potentially `total_balance`? Would return precompiled USDT-denominated balance of a (bybit::wallet/binance::account)
3030
// 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
3131
// to negate confusion could add a `total_balance` endpoint
@@ -147,3 +147,70 @@ pub struct AssetBalance {
147147
//margin_available: bool,
148148
pub timestamp: i64,
149149
}
150+
151+
pub trait MarketTrait {
152+
type Client: Exchange;
153+
fn client(&self) -> Self::Client;
154+
}
155+
156+
//#[derive(Debug, Clone, Copy)]
157+
//pub enum Market {
158+
// Binance(binance::Market),
159+
// Bybit(bybit::Market),
160+
// //TODO
161+
//}
162+
//impl Default for Market {
163+
// fn default() -> Self {
164+
// Self::Binance(binance::Market::default())
165+
// }
166+
//}
167+
//
168+
//impl std::fmt::Display for Market {
169+
// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
170+
// match self {
171+
// Market::Binance(m) => write!(f, "Binance/{}", m),
172+
// Market::Bybit(m) => write!(f, "Bybit/{}", m),
173+
// }
174+
// }
175+
//}
176+
//
177+
//impl std::str::FromStr for Market {
178+
// type Err = eyre::Error;
179+
//
180+
// fn from_str(s: &str) -> Result<Self> {
181+
// let parts: Vec<&str> = s.split('/').collect();
182+
// if parts.len() != 2 {
183+
// return Err(eyre::eyre!("Invalid market string: {}", s));
184+
// }
185+
// let exchange = parts[0];
186+
// let sub_market = parts[1];
187+
// match exchange.to_lowercase().as_str() {
188+
// "binance" => Ok(Self::Binance(sub_market.parse()?)),
189+
// "bybit" => Ok(Self::Bybit({
190+
// match sub_market.parse() {
191+
// Ok(m) => m,
192+
// Err(e) => match sub_market.to_lowercase() == "futures" {
193+
// true => bybit::Market::Linear,
194+
// false => bail!(e),
195+
// }
196+
// }
197+
// })),
198+
// _ => bail!("Invalid market string: {}", s),
199+
// }
200+
// }
201+
//}
202+
//impl From<Market> for String {
203+
// fn from(value: Market) -> Self {
204+
// value.to_string()
205+
// }
206+
//}
207+
//impl From<String> for Market {
208+
// fn from(value: String) -> Self {
209+
// value.parse().unwrap()
210+
// }
211+
//}
212+
//impl From<&str> for Market {
213+
// fn from(value: &str) -> Self {
214+
// value.parse().unwrap()
215+
// }
216+
//}

0 commit comments

Comments
 (0)