use anyhow::{Context, Ok};
use serde_json::{from_value, Value};
use crate::{model::binance_model::{BinanceRequest, BinanceSymbol, Endpoint, Kline, Klines, Ticker, Tickers}, port::binance_port::CommonPort};
use crate::model::binance_model::{BaseUrl, CommonEndpoint};
use super::adapter_utils;
pub struct BinanceCommon {
}
impl BinanceCommon {
pub fn new() -> Self{
BinanceCommon {
}
}
}
impl BinanceCommon {
fn parse_binance_kline(&self, symbol: String, interval: String, value: Value, idx: u64) -> anyhow::Result<Kline>{
let arr = value.as_array().ok_or_else(|| anyhow::anyhow!("Expected array"))?;
if arr.len() < 7 {
return Err(anyhow::anyhow!("Array too short for Kline"));
}
Ok(Kline {
symbol,
interval,
open_time: arr[0].as_u64().unwrap_or(0),
open: arr[1].as_str().unwrap_or("0.0").parse::<f64>().unwrap_or(0.0),
high: arr[2].as_str().unwrap_or("0.0").parse::<f64>().unwrap_or(0.0),
low: arr[3].as_str().unwrap_or("0.0").parse::<f64>().unwrap_or(0.0),
close: arr[4].as_str().unwrap_or("0.0").parse::<f64>().unwrap_or(0.0),
volume: arr[5].as_str().unwrap_or("0.0").parse::<f64>().unwrap_or(0.0),
close_time: arr[6].as_u64().unwrap_or(0),
idx: idx,
})
}
}
impl CommonPort for BinanceCommon{
async fn get_kline(&self, symbol: String, interval: &str, limit: Option<i32>) -> anyhow::Result<Klines> {
let common_endpoint = CommonEndpoint::Klines { symbol: symbol.to_string(), interval: interval.to_string(), limit: limit };
let binance_request = BinanceRequest::new(BaseUrl::future, common_endpoint);
let res = adapter_utils::request("get", binance_request).await?;
let parsed: Value = serde_json::from_str(res.as_str()).context("fail to parse json")?;
let klines: Vec<Kline> = parsed
.as_array()
.expect("error:")
.iter()
.enumerate()
.map(|(i, c)| {
let kline = self.parse_binance_kline(symbol.clone(), interval.to_string(), c.clone(), i as u64).unwrap_or(Kline::default());
kline
})
.collect();
Ok(Klines::new(klines))
}
async fn get_symbol_list(&self) -> anyhow::Result<Vec<String>> {
let common_endpoint = CommonEndpoint::ExchnageInfo;
let binance_request = BinanceRequest::new(BaseUrl::future, common_endpoint);
let res = adapter_utils::request("get", binance_request).await?;
let v: Value = serde_json::from_str(res.as_str()).context("fail to parse jsono")?;
let symboles_value = &v["symbols"];
let symbols: Vec<BinanceSymbol> = from_value(symboles_value.clone()).context("symbols parsing fail")?;
let symbol_vec: Vec<String> = symbols.iter()
.filter(|s| {
s.symbol.ends_with("USDT")
})
.map(|s| {
s.symbol.clone()
}).collect();
Ok(symbol_vec)
}
async fn get_symbol_with_volume(&self) -> anyhow::Result<Vec<Ticker>> {
let common_endpoint = CommonEndpoint::Ticker;
let binance_request = BinanceRequest::new(BaseUrl::future, common_endpoint);
let res = adapter_utils::request("get", binance_request).await?;
let mut parsed: Vec<Ticker> = serde_json::from_str(res.as_str()).context("fail to parse json")?;
parsed.sort_by(|a, b| {
let a: f64 = a.quote_volume.parse().unwrap();
let b: f64 = b.quote_volume.parse().unwrap();
b.partial_cmp(&a).unwrap()
});
let parsed: Vec<_> = parsed.iter()
.filter(|t|{
t.symbol.ends_with("USDT")
})
.map(|t| t.clone())
.collect();
Ok(parsed)
}
}