use crate::api::comma_joined;
use crate::client::RevolutXClient;
use crate::error::Result;
use crate::model::Data;
use crate::model::common::dash_symbol;
use crate::model::market_data::{Candle, LastTrades, OrderBook, Tickers};
use crate::transport::{RequestSpec, encode_component};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CandleInterval {
OneMinute,
FiveMinutes,
FifteenMinutes,
ThirtyMinutes,
OneHour,
FourHours,
OneDay,
TwoDays,
FourDays,
OneWeek,
TwoWeeks,
FourWeeks,
}
impl CandleInterval {
pub const fn minutes(self) -> i32 {
match self {
Self::OneMinute => 1,
Self::FiveMinutes => 5,
Self::FifteenMinutes => 15,
Self::ThirtyMinutes => 30,
Self::OneHour => 60,
Self::FourHours => 240,
Self::OneDay => 1440,
Self::TwoDays => 2880,
Self::FourDays => 5760,
Self::OneWeek => 10080,
Self::TwoWeeks => 20160,
Self::FourWeeks => 40320,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct CandlesQuery {
pub interval: Option<CandleInterval>,
pub since: Option<i64>,
pub until: Option<i64>,
}
impl CandlesQuery {
fn to_query(&self) -> Vec<(String, String)> {
let mut query = Vec::new();
if let Some(interval) = self.interval {
query.push(("interval".into(), interval.minutes().to_string()));
}
if let Some(since) = self.since {
query.push(("since".into(), since.to_string()));
}
if let Some(until) = self.until {
query.push(("until".into(), until.to_string()));
}
query
}
}
pub struct MarketDataApi<'a> {
client: &'a RevolutXClient,
}
impl<'a> MarketDataApi<'a> {
pub(crate) const fn new(client: &'a RevolutXClient) -> Self {
Self { client }
}
pub async fn order_book(&self, symbol: &str) -> Result<OrderBook> {
let path = format!("/order-book/{}", encode_component(&dash_symbol(symbol)));
self.client.send_json(RequestSpec::get(path)).await
}
pub async fn order_book_with_limit(&self, symbol: &str, limit: u32) -> Result<OrderBook> {
let path = format!("/order-book/{}", encode_component(&dash_symbol(symbol)));
self.client
.send_json(RequestSpec::get(path).with_query(vec![("limit".into(), limit.to_string())]))
.await
}
pub async fn public_order_book(&self, symbol: &str) -> Result<OrderBook> {
let path = format!(
"/public/order-book/{}",
encode_component(&dash_symbol(symbol))
);
self.client.send_json(RequestSpec::get(path).public()).await
}
pub async fn candles(&self, symbol: &str, query: &CandlesQuery) -> Result<Vec<Candle>> {
let path = format!("/candles/{}", encode_component(&dash_symbol(symbol)));
let data: Data<Vec<Candle>> = self
.client
.send_json(RequestSpec::get(path).with_query(query.to_query()))
.await?;
Ok(data.data)
}
pub async fn tickers(&self) -> Result<Tickers> {
self.client.send_json(RequestSpec::get("/tickers")).await
}
pub async fn tickers_for<S: AsRef<str> + Sync>(&self, symbols: &[S]) -> Result<Tickers> {
let query = comma_joined("symbols", symbols.iter().map(|s| dash_symbol(s.as_ref())));
self.client
.send_json(RequestSpec::get("/tickers").with_query(query))
.await
}
pub async fn last_trades(&self) -> Result<LastTrades> {
self.client
.send_json(RequestSpec::get("/public/last-trades").public())
.await
}
}