#![allow(unused)]
use std::{
fmt,
sync::{Arc, OnceLock},
};
use async_trait::async_trait;
use quantoxide::{
error::Result,
models::ClientId,
trade::{SignalOperator, TradeExecutor, TradingState},
tui::TuiLogger,
};
pub mod evaluator;
pub use evaluator::{SignalAction, SignalTemplate};
#[allow(dead_code)]
pub struct SingleSignalOperatorTemplate {
trade_executor: OnceLock<Arc<dyn TradeExecutor>>,
}
#[allow(dead_code)]
impl SingleSignalOperatorTemplate {
pub fn new() -> Box<Self> {
Box::new(Self {
trade_executor: OnceLock::new(),
})
}
fn trade_executor(&self) -> Result<&Arc<dyn TradeExecutor>> {
self.trade_executor
.get()
.ok_or_else(|| "trade executor was not set".into())
}
}
#[async_trait]
impl SignalOperator<SignalTemplate> for SingleSignalOperatorTemplate {
fn set_trade_executor(&mut self, trade_executor: Arc<dyn TradeExecutor>) -> Result<()> {
self.trade_executor
.set(trade_executor)
.map_err(|_| "trade executor was already set".into())
}
async fn process_signal(&self, signal: &SignalTemplate) -> Result<()> {
let trade_executor = self.trade_executor()?;
match &signal.action {
SignalAction::Long { price, strength } => {}
SignalAction::Short { price, strength } => {}
SignalAction::CloseLong => {}
SignalAction::CloseShort => {}
SignalAction::Wait => {}
}
Ok(())
}
}
#[derive(Debug, Clone)]
pub enum SupportedSignal {
Template(SignalTemplate),
}
impl From<SignalTemplate> for SupportedSignal {
fn from(signal: SignalTemplate) -> Self {
Self::Template(signal)
}
}
impl fmt::Display for SupportedSignal {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SupportedSignal::Template(signal) => {
write!(f, "Template signal at {}: {:?}", signal.time, signal.action)
}
}
}
}
pub struct MultiSignalOperatorTemplate {
trade_executor: OnceLock<Arc<dyn TradeExecutor>>,
logger: Option<Arc<dyn TuiLogger>>,
}
impl MultiSignalOperatorTemplate {
pub fn new() -> Box<Self> {
Box::new(Self {
trade_executor: OnceLock::new(),
logger: None,
})
}
pub fn with_logger(logger: Arc<dyn TuiLogger>) -> Box<Self> {
Box::new(Self {
trade_executor: OnceLock::new(),
logger: Some(logger),
})
}
fn trade_executor(&self) -> Result<&Arc<dyn TradeExecutor>> {
if let Some(trade_executor) = self.trade_executor.get() {
return Ok(trade_executor);
}
Err("trade executor was not set".into())
}
#[allow(dead_code)]
async fn log(&self, text: String) -> Result<()> {
if let Some(logger) = self.logger.as_ref() {
logger.log(text).await?;
}
Ok(())
}
}
impl Default for MultiSignalOperatorTemplate {
fn default() -> Self {
Self {
trade_executor: OnceLock::new(),
logger: None,
}
}
}
#[async_trait]
impl SignalOperator<SupportedSignal> for MultiSignalOperatorTemplate {
fn set_trade_executor(&mut self, trade_executor: Arc<dyn TradeExecutor>) -> Result<()> {
if self.trade_executor.set(trade_executor).is_err() {
return Err("trade executor was already set".into());
}
Ok(())
}
async fn process_signal(&self, signal: &SupportedSignal) -> Result<()> {
let trade_executor = self.trade_executor()?;
let trading_state: TradingState = trade_executor.trading_state().await?;
let iteration_time = trading_state.last_tick_time();
let balance = trading_state.balance();
let market_price = trading_state.market_price();
let running_trades_map = trading_state.running_map();
match signal {
SupportedSignal::Template(template_signal) => {
match &template_signal.action {
SignalAction::Long { price, strength } => {}
SignalAction::Short { price, strength } => {}
SignalAction::CloseLong => {}
SignalAction::CloseShort => {}
SignalAction::Wait => {}
}
} }
for ((creation_time, trade_id), (trade, tsl)) in running_trades_map {
let client_id = trade.client_id(); let side = trade.side();
let pl = trade.est_pl(market_price);
}
Ok(())
}
}