//! Shared types for AlgoArena - Strategy Backtesting Battleground. //! //! This crate defines the IPC types for multi-agent trading simulation. use serde::{Deserialize, Serialize}; // ============================================================================ // Market Types // ============================================================================ /// Market state snapshot. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MarketState { /// Current timestamp (step). pub step: usize, /// Current prices for each asset. pub prices: Vec, /// Price history (for lookback). pub price_history: Vec>, /// Volume for each asset. pub volumes: Vec, /// Market indicators. pub indicators: MarketIndicators, } /// Market-wide indicators. #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct MarketIndicators { /// Market return (%). pub market_return: f64, /// Volatility. pub volatility: f64, /// Trend strength (positive = bullish, negative = bearish). pub trend: f64, } /// Asset configuration. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AssetConfig { /// Asset symbol. pub symbol: String, /// Initial price. pub initial_price: f64, /// Daily volatility. pub volatility: f64, /// Expected drift (daily). pub drift: f64, } // ============================================================================ // Order and Execution Types // ============================================================================ /// Order side. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum OrderSide { /// Buy. Buy, /// Sell. Sell, } /// Order type. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum OrderType { /// Market order. Market, /// Limit order. Limit, } /// A trading order. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Order { /// Agent ID. pub agent_id: String, /// Asset index. pub asset_idx: usize, /// Side. pub side: OrderSide, /// Order type. pub order_type: OrderType, /// Quantity (shares). pub quantity: f64, /// Limit price (for limit orders). pub limit_price: Option, } /// Order execution result. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Execution { /// Original order. pub order: Order, /// Filled quantity. pub filled_quantity: f64, /// Average fill price. pub fill_price: f64, /// Transaction cost. pub transaction_cost: f64, /// Slippage. pub slippage: f64, /// Whether fully filled. pub is_filled: bool, } // ============================================================================ // Agent Types // ============================================================================ /// Strategy type for an agent. #[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, Hash)] pub enum StrategyType { /// Buy and hold. BuyAndHold, /// Momentum following. Momentum, /// Mean reversion. MeanReversion, /// Trend following (moving average crossover). TrendFollowing, /// Random (baseline). Random, /// Custom / RL-based. Custom, } /// Agent configuration. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AgentConfig { /// Agent ID. pub id: String, /// Agent name. pub name: String, /// Strategy type. pub strategy: StrategyType, /// Initial capital. pub initial_capital: f64, /// Parameters. pub parameters: AgentParameters, } /// Agent parameters. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AgentParameters { /// Lookback window. pub lookback: usize, /// Position sizing (fraction of capital). pub position_size: f64, /// Stop loss (%). pub stop_loss: Option, /// Take profit (%). pub take_profit: Option, /// Short MA period (for trend following). pub short_ma_period: usize, /// Long MA period. pub long_ma_period: usize, /// Threshold for mean reversion. pub reversion_threshold: f64, /// Momentum threshold. pub momentum_threshold: f64, } impl Default for AgentParameters { fn default() -> Self { Self { lookback: 20, position_size: 0.1, stop_loss: Some(0.05), take_profit: Some(0.10), short_ma_period: 10, long_ma_period: 50, reversion_threshold: 2.0, momentum_threshold: 0.01, } } } /// Agent state during simulation. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AgentState { /// Agent ID. pub agent_id: String, /// Current cash. pub cash: f64, /// Holdings (shares per asset). pub holdings: Vec, /// Portfolio value. pub portfolio_value: f64, /// P&L history. pub pnl_history: Vec, /// Number of trades. pub trade_count: usize, } // ============================================================================ // Tournament Types // ============================================================================ /// Tournament configuration. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TournamentConfig { /// Tournament name. pub name: String, /// Number of simulation steps. pub num_steps: usize, /// Asset configurations. pub assets: Vec, /// Agent configurations. pub agents: Vec, /// Transaction cost (basis points). pub transaction_cost_bps: f64, /// Random seed. pub seed: Option, } /// Tournament result. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TournamentResult { /// Tournament config. pub config: TournamentConfig, /// Agent results (sorted by rank). pub rankings: Vec, /// Final price paths. pub price_paths: Vec>, /// Market statistics. pub market_stats: MarketStats, } /// Individual agent result. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct AgentResult { /// Agent ID. pub agent_id: String, /// Agent name. pub agent_name: String, /// Strategy type. pub strategy: StrategyType, /// Final rank (1 = best). pub rank: usize, /// Final portfolio value. pub final_value: f64, /// Total return (%). pub total_return: f64, /// Sharpe ratio. pub sharpe_ratio: f64, /// Maximum drawdown (%). pub max_drawdown: f64, /// Win rate (% of profitable trades). pub win_rate: f64, /// Number of trades. pub trade_count: usize, /// P&L history. pub pnl_history: Vec, } /// Market statistics. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct MarketStats { /// Market return over period. pub market_return: f64, /// Market volatility. pub market_volatility: f64, /// Best performing asset. pub best_asset: String, /// Worst performing asset. pub worst_asset: String, } // ============================================================================ // Sample Data Functions // ============================================================================ /// Create default asset configurations. #[must_use] pub fn default_assets() -> Vec { vec![ AssetConfig { symbol: "SPY".to_string(), initial_price: 500.0, volatility: 0.012, drift: 0.0003, }, AssetConfig { symbol: "QQQ".to_string(), initial_price: 400.0, volatility: 0.015, drift: 0.0004, }, AssetConfig { symbol: "TLT".to_string(), initial_price: 90.0, volatility: 0.010, drift: 0.0001, }, ] } /// Create default agent configurations. #[must_use] pub fn default_agents() -> Vec { vec![ AgentConfig { id: "momentum_1".to_string(), name: "Momentum Master".to_string(), strategy: StrategyType::Momentum, initial_capital: 100_000.0, parameters: AgentParameters { lookback: 20, momentum_threshold: 0.02, ..Default::default() }, }, AgentConfig { id: "reversion_1".to_string(), name: "Mean Machine".to_string(), strategy: StrategyType::MeanReversion, initial_capital: 100_000.0, parameters: AgentParameters { lookback: 30, reversion_threshold: 2.0, ..Default::default() }, }, AgentConfig { id: "trend_1".to_string(), name: "Trend Tracker".to_string(), strategy: StrategyType::TrendFollowing, initial_capital: 100_000.0, parameters: AgentParameters { short_ma_period: 10, long_ma_period: 50, ..Default::default() }, }, AgentConfig { id: "buyhold_1".to_string(), name: "Buy & Hold".to_string(), strategy: StrategyType::BuyAndHold, initial_capital: 100_000.0, parameters: AgentParameters::default(), }, AgentConfig { id: "random_1".to_string(), name: "Random Walker".to_string(), strategy: StrategyType::Random, initial_capital: 100_000.0, parameters: AgentParameters::default(), }, ] } /// Create a sample tournament configuration. #[must_use] pub fn sample_tournament() -> TournamentConfig { TournamentConfig { name: "Strategy Showdown".to_string(), num_steps: 252, // One year assets: default_assets(), agents: default_agents(), transaction_cost_bps: 10.0, seed: Some(42), } } // ============================================================================ // Tests // ============================================================================ #[cfg(test)] mod tests { use super::*; #[test] fn test_order_creation() { let order = Order { agent_id: "test".to_string(), asset_idx: 0, side: OrderSide::Buy, order_type: OrderType::Market, quantity: 10.0, limit_price: None, }; assert_eq!(order.side, OrderSide::Buy); assert_eq!(order.quantity, 10.0); } #[test] fn test_agent_parameters_default() { let params = AgentParameters::default(); assert_eq!(params.lookback, 20); assert!(params.stop_loss.is_some()); } #[test] fn test_default_assets() { let assets = default_assets(); assert_eq!(assets.len(), 3); assert_eq!(assets[0].symbol, "SPY"); } #[test] fn test_default_agents() { let agents = default_agents(); assert_eq!(agents.len(), 5); // Check strategy diversity let strategies: Vec<_> = agents.iter().map(|a| a.strategy).collect(); assert!(strategies.contains(&StrategyType::Momentum)); assert!(strategies.contains(&StrategyType::MeanReversion)); } #[test] fn test_sample_tournament() { let tournament = sample_tournament(); assert_eq!(tournament.num_steps, 252); assert!(!tournament.assets.is_empty()); assert!(!tournament.agents.is_empty()); } #[test] fn test_serialization() { let config = sample_tournament(); let json = serde_json::to_string(&config).unwrap(); assert!(json.contains("Strategy Showdown")); let parsed: TournamentConfig = serde_json::from_str(&json).unwrap(); assert_eq!(parsed.name, config.name); } }