#![allow(unused)]
use std::sync::{Arc, OnceLock};
use async_trait::async_trait;
use quantoxide::{
error::Result,
models::{Lookback, MinIterationInterval, OhlcCandleRow, OhlcResolution},
trade::{RawOperator, TradeExecutor, TradingState},
tui::TuiLogger,
};
enum LogOutput {
Disabled,
Stdout,
Tui(Arc<dyn TuiLogger>),
}
pub struct RawOperatorTemplate {
trade_executor: OnceLock<Arc<dyn TradeExecutor>>,
output: LogOutput,
}
impl RawOperatorTemplate {
fn new(output: LogOutput) -> Box<Self> {
Box::new(Self {
trade_executor: OnceLock::new(),
output,
})
}
pub fn boxed() -> Box<Self> {
Self::new(LogOutput::Disabled)
}
pub fn enable_stdout_logger(mut self: Box<Self>) -> Box<Self> {
self.output = LogOutput::Stdout;
self
}
pub fn enable_tui_logger(mut self: Box<Self>, logger: Arc<dyn TuiLogger>) -> Box<Self> {
self.output = LogOutput::Tui(logger);
self
}
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())
}
async fn log(&self, text: String) -> Result<()> {
match &self.output {
LogOutput::Disabled => {}
LogOutput::Stdout => println!("{text}"),
LogOutput::Tui(logger) => logger.log(text).await?,
}
Ok(())
}
}
#[async_trait]
impl RawOperator for RawOperatorTemplate {
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(())
}
fn lookback(&self) -> Option<Lookback> {
Some(Lookback::new(OhlcResolution::FifteenMinutes, 10).expect("is valid"))
}
fn min_iteration_interval(&self) -> MinIterationInterval {
MinIterationInterval::MIN }
async fn iterate(&self, candles: &[OhlcCandleRow]) -> 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();
self.log(format!(
"Iteration: time={iteration_time}, market_price={market_price}",
))
.await?;
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(())
}
}