use crate::traits::Exchange;
use crate::strategy::{Strategy, Context};
use crate::ws::handler::{MarketEvent, AccountEvent, EventHandler};
use crate::risk::{PositionSizer, RiskConfig};
use crate::types::{Side, OrderType};
use tokio::sync::broadcast;
use std::sync::Arc;
use tokio::sync::RwLock;
#[derive(Debug, Clone)]
pub enum Signal {
Buy { symbol: String, size: String, price: Option<String> },
Sell { symbol: String, size: String, price: Option<String> },
Close { symbol: String },
Hold,
}
#[derive(Debug, Clone, Default)]
pub struct EngineState {
pub running: bool,
pub total_trades: u64,
pub winning_trades: u64,
pub total_pnl: f64,
}
pub struct Engine<E: Exchange + Clone + Send + Sync + 'static> {
exchange: E,
position_sizer: PositionSizer,
state: Arc<RwLock<EngineState>>,
}
impl<E: Exchange + Clone + Send + Sync + 'static> Engine<E> {
pub fn new(exchange: E, risk_config: RiskConfig) -> Self {
Engine {
exchange,
position_sizer: PositionSizer::new(risk_config),
state: Arc::new(RwLock::new(EngineState::default())),
}
}
pub async fn run<S: Strategy + Send + Sync + 'static>(
&self,
strategy: S,
mut market_rx: broadcast::Receiver<MarketEvent>,
mut account_rx: broadcast::Receiver<AccountEvent>,
) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
{
let mut state = self.state.write().await;
state.running = true;
}
loop {
tokio::select! {
Ok(event) = market_rx.recv() => {
match event {
MarketEvent::Ticker { symbol, price } => {
let context = Context {
exchange_name: "weex".to_string(),
symbol: symbol.clone(),
price,
balance: 0.0, position: 0.0,
};
tracing::debug!("Ticker: {} @ {}", symbol, price);
}
_ => {}
}
}
Ok(event) = account_rx.recv() => {
match event {
AccountEvent::OrderUpdate { order_id, status, filled_size } => {
tracing::info!("Order {} -> {} (filled: {})", order_id, status, filled_size);
if status == "filled" {
let mut state = self.state.write().await;
state.total_trades += 1;
}
}
AccountEvent::PositionUpdate { symbol, size, pnl, .. } => {
tracing::info!("Position {} size={} pnl={}", symbol, size, pnl);
}
_ => {}
}
}
}
}
}
pub async fn execute_signal(&self, signal: Signal) -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
match signal {
Signal::Buy { symbol, size, price } => {
tracing::info!("Executing BUY {} size={}", symbol, size);
}
Signal::Sell { symbol, size, price } => {
tracing::info!("Executing SELL {} size={}", symbol, size);
}
Signal::Close { symbol } => {
tracing::info!("Closing position {}", symbol);
}
Signal::Hold => {}
}
Ok(())
}
pub async fn get_state(&self) -> EngineState {
self.state.read().await.clone()
}
}