Skip to content

Commit 83d8e67

Browse files
committed
chore: switch to generic KlinesRangeRequest
1 parent 585d49a commit 83d8e67

File tree

7 files changed

+109
-27
lines changed

7 files changed

+109
-27
lines changed

examples/binance/market.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ async fn main() {
1212

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

15-
let klines = b.futures_klines(("BTC", "USDT").into(), "1m".into(), 2, None, None).await.unwrap();
15+
let klines = b.futures_klines(("BTC", "USDT").into(), "1m".into(), 2.into()).await.unwrap();
1616
let price = b.futures_price(("BTC", "USDT").into()).await.unwrap();
1717
dbg!(&klines, price);
1818

examples/bybit/market.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ async fn main() {
1616
// .expect("failed to get ticker");
1717
//println!("Ticker:\n{ticker}");
1818

19-
let klines = bb.futures_klines(("BTC", "USDT").into(), "1m".into(), 2, None, None).await.unwrap();
19+
let klines = bb.futures_klines(("BTC", "USDT").into(), "1m".into(), 2.into()).await.unwrap();
2020
dbg!(&klines);
2121

2222
if let (Ok(key), Ok(secret)) = (env::var("BYBIT_TIGER_READ_KEY"), env::var("BYBIT_TIGER_READ_SECRET")) {

v_exchanges/src/binance/futures/market.rs

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::fmt;
2+
13
use chrono::{DateTime, TimeZone, Utc};
24
//HACK: Methods should be implemented on the central interface struct, following <https://github.com/wisespace-io/binance-rs>.
35
use color_eyre::eyre::{self, Error, Result};
@@ -11,17 +13,52 @@ use v_utils::{
1113
utils::filter_nulls,
1214
};
1315

14-
use crate::core::Klines;
16+
use crate::core::{Klines, KlinesRequestRange};
17+
18+
//MOVE: centralized error module
19+
#[derive(Debug)]
20+
struct LimitOutOfRangeError {
21+
allowed: std::ops::RangeInclusive<u32>,
22+
provided: u32,
23+
}
24+
impl fmt::Display for LimitOutOfRangeError {
25+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26+
write!(f, "Limit out of range. Allowed: {:?}, provided: {}", self.allowed, self.provided)
27+
}
28+
}
29+
impl std::error::Error for LimitOutOfRangeError {}
1530

1631
// klines {{{
17-
pub async fn klines(client: &v_exchanges_adapters::Client, pair: Pair, tf: Timeframe, limit: u32, start_time: Option<u64>, end_time: Option<u64>) -> Result<Klines> {
18-
let mut params = filter_nulls(json!({
32+
pub async fn klines(client: &v_exchanges_adapters::Client, pair: Pair, tf: Timeframe, range: KlinesRequestRange) -> Result<Klines> {
33+
let range_json = match range {
34+
KlinesRequestRange::StartEnd { start, end } => json!({
35+
"startTime": start.timestamp_millis(),
36+
"endTime": end.timestamp_millis(),
37+
}),
38+
KlinesRequestRange::Limit(limit) => {
39+
let allowed_range = 1..=1000;
40+
if !allowed_range.contains(&limit) {
41+
return Err(LimitOutOfRangeError {
42+
allowed: allowed_range,
43+
provided: limit,
44+
}
45+
.into());
46+
}
47+
json!({
48+
"limit": limit,
49+
})
50+
}
51+
};
52+
let mut base_params = filter_nulls(json!({
1953
"symbol": pair.to_string(),
2054
"interval": tf.format_binance()?,
21-
"limit": limit,
22-
"startTime": start_time,
23-
"endTime": end_time,
2455
}));
56+
57+
let mut base_map = base_params.as_object().unwrap().clone();
58+
let range_map = range_json.as_object().unwrap();
59+
base_map.extend(range_map.clone());
60+
let params = filter_nulls(serde_json::Value::Object(base_map));
61+
2562
let kline_responses: Vec<KlineResponse> = client.get("/fapi/v1/klines", &params, [BinanceOption::HttpUrl(BinanceHttpUrl::FuturesUsdM)]).await.unwrap();
2663

2764
let r_len = kline_responses.len();

v_exchanges/src/binance/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ use v_utils::{
77
trades::{Asset, Pair, Timeframe},
88
};
99

10-
use crate::core::{AssetBalance, Exchange, Klines};
10+
use crate::core::{AssetBalance, Exchange, Klines, KlinesRequestRange};
1111

1212
#[derive(Clone, Debug, Default, Deref, DerefMut)]
1313
pub struct Binance(pub Client);
1414

1515
//? 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?
1616
impl Exchange for Binance {
17-
async fn futures_klines(&self, symbol: Pair, tf: Timeframe, limit: u32, start_time: Option<u64>, end_time: Option<u64>) -> Result<Klines> {
18-
futures::market::klines(&self.0, symbol, tf, limit, start_time, end_time).await
17+
async fn futures_klines(&self, symbol: Pair, tf: Timeframe, range: KlinesRequestRange) -> Result<Klines> {
18+
futures::market::klines(&self.0, symbol, tf, range).await
1919
}
2020

2121
async fn futures_price(&self, symbol: Pair) -> Result<f64> {

v_exchanges/src/bybit/market.rs

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use v_utils::{
1212
utils::filter_nulls,
1313
};
1414

15-
use crate::core::Klines;
15+
use crate::core::{Klines, KlinesRequestRange};
1616

1717
//MOVE: centralized error module
1818
#[derive(Debug)]
@@ -27,20 +27,37 @@ impl fmt::Display for LimitOutOfRangeError {
2727
}
2828
impl std::error::Error for LimitOutOfRangeError {}
2929

30-
pub async fn klines(client: &v_exchanges_adapters::Client, pair: Pair, tf: Timeframe, limit: u32, start_time: Option<u64>, end_time: Option<u64>) -> Result<Klines> {
31-
let range = 1..=1000;
32-
if !range.contains(&limit) {
33-
return Err(LimitOutOfRangeError { allowed: range, provided: limit }.into());
34-
}
35-
36-
let mut params = filter_nulls(json!({
30+
pub async fn klines(client: &v_exchanges_adapters::Client, pair: Pair, tf: Timeframe, range: KlinesRequestRange) -> Result<Klines> {
31+
let range_json = match range {
32+
KlinesRequestRange::StartEnd { start, end } => json!({
33+
"startTime": start.timestamp_millis(),
34+
"endTime": end.timestamp_millis(),
35+
}),
36+
KlinesRequestRange::Limit(limit) => {
37+
let allowed_range = 1..=1000;
38+
if !allowed_range.contains(&limit) {
39+
return Err(LimitOutOfRangeError {
40+
allowed: allowed_range,
41+
provided: limit,
42+
}
43+
.into());
44+
}
45+
json!({
46+
"limit": limit,
47+
})
48+
}
49+
};
50+
let mut base_params = filter_nulls(json!({
3751
"category": "linear", // can be ["linear", "inverse", "spot"] afaiu, could drive some generics with this later, but for now hardcode
3852
"symbol": pair.to_string(),
3953
"interval": tf.format_bybit()?,
40-
"limit": limit,
41-
"startTime": start_time,
42-
"endTime": end_time,
4354
}));
55+
56+
let mut base_map = base_params.as_object().unwrap().clone();
57+
let range_map = range_json.as_object().unwrap();
58+
base_map.extend(range_map.clone());
59+
let params = filter_nulls(serde_json::Value::Object(base_map));
60+
4461
let kline_response: KlineResponse = client.get("/v5/market/kline", &params, [BybitOption::Default]).await.unwrap();
4562

4663
let mut klines = Vec::new();

v_exchanges/src/bybit/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@ use derive_more::derive::{Deref, DerefMut};
66
use v_exchanges_adapters::{Client, bybit};
77
use v_utils::trades::{Asset, Pair, Timeframe};
88

9-
use crate::core::{AssetBalance, Exchange, Klines};
9+
use crate::core::{AssetBalance, Exchange, Klines, KlinesRequestRange};
1010

1111
#[derive(Clone, Debug, Default, Deref, DerefMut)]
1212
pub struct Bybit(pub Client);
1313

1414
//? 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?
1515
impl Exchange for Bybit {
16-
async fn futures_klines(&self, symbol: Pair, tf: Timeframe, limit: u32, start_time: Option<u64>, end_time: Option<u64>) -> Result<Klines> {
17-
market::klines(&self.0, symbol, tf, limit, start_time, end_time).await
16+
async fn futures_klines(&self, symbol: Pair, tf: Timeframe, range: KlinesRequestRange) -> Result<Klines> {
17+
market::klines(&self.0, symbol, tf, range).await
1818
}
1919

2020
async fn futures_price(&self, symbol: Pair) -> Result<f64> {

v_exchanges/src/core.rs

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use v_utils::trades::{Asset, Kline, Pair, Timeframe};
88

99
pub trait Exchange {
1010
//? should I have Self::Pair too? Like to catch the non-existent ones immediately? Although this would increase the error surface on new listings.
11-
fn futures_klines(&self, symbol: Pair, tf: Timeframe, limit: u32, start_time: Option<u64>, end_time: Option<u64>) -> impl std::future::Future<Output = Result<Klines>> + Send;
11+
fn futures_klines(&self, symbol: Pair, tf: Timeframe, range: KlinesRequestRange) -> impl std::future::Future<Output = Result<Klines>> + Send;
1212
fn futures_price(&self, symbol: Pair) -> impl std::future::Future<Output = Result<f64>> + Send;
1313

1414
// Defined in terms of actors
@@ -45,13 +45,41 @@ pub struct Klines {
4545
//? not sure what to do about oi here
4646
/// [Kline]s series that is _guaranteed to not have any gaps in kline data_.
4747
#[derive(Clone, Debug, Default)]
48-
struct FullKlines(Klines);
48+
pub struct FullKlines(Klines);
4949
impl TryFrom<Klines> for FullKlines {
5050
type Error = color_eyre::eyre::Report;
5151
fn try_from(value: Klines) -> Result<Self> {
5252
todo!();
5353
}
5454
}
55+
56+
#[derive(Clone, Debug, Copy)]
57+
pub enum KlinesRequestRange {
58+
/// Preferred way of defining the range
59+
StartEnd{start: DateTime<Utc>, end: DateTime<Utc>},
60+
/// For quick and dirty
61+
Limit(u32),
62+
}
63+
impl Default for KlinesRequestRange {
64+
fn default() -> Self {
65+
KlinesRequestRange::StartEnd { start: DateTime::default(), end: DateTime::default() }
66+
}
67+
}
68+
impl From<u32> for KlinesRequestRange {
69+
fn from(value: u32) -> Self {
70+
KlinesRequestRange::Limit(value)
71+
}
72+
}
73+
impl From<(DateTime<Utc>, DateTime<Utc>)> for KlinesRequestRange {
74+
fn from(value: (DateTime<Utc>, DateTime<Utc>)) -> Self {
75+
KlinesRequestRange::StartEnd { start: value.0, end: value.1 }
76+
}
77+
}
78+
impl From<(i64, i64)> for KlinesRequestRange {
79+
fn from(value: (i64, i64)) -> Self {
80+
KlinesRequestRange::StartEnd { start: DateTime::from_timestamp_millis(value.0).unwrap(), end: DateTime::from_timestamp_millis(value.1).unwrap()}
81+
}
82+
}
5583
//,}}}
5684

5785
#[derive(Clone, Debug, Default, Copy)]

0 commit comments

Comments
 (0)