v_exchanges 0.17.1

Implementations of HTTP/HTTPS/WebSocket API methods for some crypto exchanges, using [crypto-botters](<https://github.com/negi-grass/crypto-botters>) framework
Documentation
pub mod data; // interfaced with directly, not through `Exchange` trait, thus must be public.
pub mod perp; // public for accessing order placement and income history functions
use std::collections::BTreeMap;
mod market;
mod spot;
mod ws;
use adapters::{
	Client, GetOptions,
	binance::{BinanceOption, BinanceOptions},
};
use secrecy::SecretString;
use v_utils::trades::{Pair, Timeframe};

use crate::{
	BookUpdate, ExchangeError, ExchangeInfo, ExchangeName, ExchangeResult, ExchangeStream, Klines, MethodError, RequestRange, Trade,
	core::{ExchangeImpl, Instrument, PersonalInfo, Symbol},
};

#[derive(Clone, Debug, Default, derive_more::Deref, derive_more::DerefMut)]
pub struct Binance(pub Client);

#[async_trait::async_trait]
impl ExchangeImpl for Binance {
	fn name(&self) -> ExchangeName {
		ExchangeName::Binance
	}

	fn auth(&mut self, pubkey: String, secret: SecretString) {
		self.update_default_option(BinanceOption::Pubkey(pubkey));
		self.update_default_option(BinanceOption::Secret(secret));
	}

	fn set_recv_window(&mut self, recv_window: std::time::Duration) {
		self.update_default_option(BinanceOption::RecvWindow(recv_window));
	}

	fn default_recv_window(&self) -> Option<std::time::Duration> {
		GetOptions::<BinanceOptions>::default_options(&**self).recv_window
	}

	async fn exchange_info(&self, instrument: Instrument) -> ExchangeResult<ExchangeInfo> {
		match instrument {
			Instrument::Perp => perp::general::exchange_info(self).await,
			_ => unimplemented!(),
		}
	}

	async fn klines(&self, symbol: Symbol, tf: Timeframe, range: RequestRange) -> ExchangeResult<Klines> {
		match symbol.instrument {
			Instrument::Spot | Instrument::Margin => market::klines(self, symbol, tf.try_into()?, range).await,
			Instrument::Perp => market::klines(self, symbol, tf.try_into()?, range).await,
			_ => Err(ExchangeError::Method(MethodError::MethodNotImplemented {
				exchange: self.name(),
				instrument: symbol.instrument,
			})),
		}
	}

	async fn prices(&self, pairs: Option<Vec<Pair>>, instrument: Instrument) -> ExchangeResult<BTreeMap<Pair, f64>> {
		match instrument {
			Instrument::Spot | Instrument::Margin => spot::market::prices(self, pairs).await,
			Instrument::Perp => perp::market::prices(self, pairs).await,
			_ => Err(ExchangeError::Method(MethodError::MethodNotImplemented { exchange: self.name(), instrument })),
		}
	}

	async fn price(&self, symbol: Symbol) -> ExchangeResult<f64> {
		match symbol.instrument {
			Instrument::Spot | Instrument::Margin => spot::market::price(self, symbol.pair).await,
			Instrument::Perp => perp::market::price(self, symbol.pair).await,
			_ => Err(ExchangeError::Method(MethodError::MethodNotImplemented {
				exchange: self.name(),
				instrument: symbol.instrument,
			})),
		}
	}

	async fn open_interest(&self, symbol: Symbol, tf: Timeframe, range: RequestRange) -> ExchangeResult<Vec<crate::core::OpenInterest>> {
		match symbol.instrument {
			Instrument::Perp => market::open_interest(self, symbol, tf.try_into()?, range).await,
			_ => Err(ExchangeError::Method(MethodError::MethodNotSupported {
				exchange: self.name(),
				instrument: symbol.instrument,
			})),
		}
	}

	async fn personal_info(&self, instrument: Instrument, recv_window: Option<std::time::Duration>) -> ExchangeResult<PersonalInfo> {
		match instrument {
			Instrument::Perp => {
				let prices = self.prices(None, instrument).await?;
				perp::account::personal_info(self, recv_window, &prices).await
			}
			Instrument::Spot | Instrument::Margin => spot::account::personal_info(self, recv_window).await,
			_ => Err(ExchangeError::Method(MethodError::MethodNotImplemented { exchange: self.name(), instrument })),
		}
	}

	fn ws_trades(&self, pairs: Vec<Pair>, instrument: Instrument) -> Result<Box<dyn ExchangeStream<Item = Trade>>, ExchangeError> {
		match instrument {
			Instrument::Perp | Instrument::Spot | Instrument::Margin => {
				let connection = ws::TradesConnection::new(self, pairs, instrument)?;
				Ok(Box::new(connection))
			}
			_ => Err(ExchangeError::Method(MethodError::MethodNotImplemented { exchange: self.name(), instrument })),
		}
	}

	fn ws_book(&self, pairs: Vec<Pair>, instrument: Instrument) -> Result<Box<dyn ExchangeStream<Item = BookUpdate>>, ExchangeError> {
		match instrument {
			Instrument::Perp | Instrument::Spot | Instrument::Margin => {
				let connection = ws::BookConnection::new(self, pairs, instrument)?;
				Ok(Box::new(connection))
			}
			_ => Err(ExchangeError::Method(MethodError::MethodNotImplemented { exchange: self.name(), instrument })),
		}
	}
}

crate::define_provider_timeframe!(
	BinanceTimeframe,
	[
		"1s", "5s", "15s", "30s", "1m", "3m", "5m", "15m", "30m", "1h", "2h", "4h", "6h", "8h", "12h", "1d", "3d", "1w", "1M"
	]
);