discretionary_engine 1.0.0

LaTeX of trading
use std::{
	collections::HashMap,
	sync::{Arc, RwLock},
};

use serde::{Deserialize, Serialize};
use tracing::instrument;

use super::BinanceExchange;
use crate::{
	exchange_apis::order_types::{Order, OrderType, StopMarketOrder},
	positions::PositionOrderId,
};

#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq)]
pub struct BinanceOrder {
	pub base_info: Order<PositionOrderId>,
	pub binance_id: Option<i64>,
	pub notional_filled: f64,
}
impl BinanceOrder {
	pub fn new(base_info: Order<PositionOrderId>) -> Self {
		Self { base_info, ..Default::default() }
	}

	pub fn to_params(&self) -> HashMap<&'static str, String> {
		let mut params = HashMap::<&'static str, String>::new();
		params.insert("symbol", self.base_info.symbol.to_string());
		params.insert("side", self.base_info.side.to_string());
		params.insert("quantity", format!("{}", self.base_info.qty_notional));

		let type_params = match &self.base_info.order_type {
			OrderType::Market => {
				let mut params = HashMap::<&'static str, String>::new();
				params.insert("type", "MARKET".to_string());
				params
			}
			OrderType::StopMarket(sm) => {
				let mut params = HashMap::<&'static str, String>::new();
				params.insert("type", "STOP_MARKET".to_string());
				params.insert("stopPrice", sm.price.to_string());
				params
			}
		};
		params.extend(type_params);

		params
	}

	#[instrument(skip(binance_exchange_arc))]
	pub async fn from_standard(mut order: Order<PositionOrderId>, binance_exchange_arc: Arc<RwLock<BinanceExchange>>) -> Self {
		let futures_symbol = {
			let lock = binance_exchange_arc.read().unwrap();
			let futures_symbol = lock
				.binance_futures_info
				.pair(&order.symbol.base, &order.symbol.quote)
				.expect("coin should have been checked earlier");
			futures_symbol.clone()
		};
		fn precision(qty: f64, precision: i32) -> f64 {
			let factor = 10_f64.powi(precision);
			(qty * factor).round() / factor
		}
		let coin_quantity_adjusted = precision(order.qty_notional, futures_symbol.quantity_precision as i32);
		order.qty_notional = coin_quantity_adjusted;

		let order_type = match &order.order_type {
			OrderType::Market => OrderType::Market,
			OrderType::StopMarket(sm) => OrderType::StopMarket(StopMarketOrder::new(precision(sm.price, futures_symbol.price_precision as i32))),
		};
		order.order_type = order_type;

		Self::new(order)
	}
}