diff --git a/Cargo.lock b/Cargo.lock index c0b91202e..79bff655d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7834,6 +7834,7 @@ dependencies = [ "async-trait", "chrono", "color-eyre", + "common", "criterion", "crossterm 0.27.0", "env_logger 0.11.8", diff --git a/adaptive-strategy/src/execution/mod.rs b/adaptive-strategy/src/execution/mod.rs index 06e7ffa5b..5174786ab 100644 --- a/adaptive-strategy/src/execution/mod.rs +++ b/adaptive-strategy/src/execution/mod.rs @@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize}; use std::collections::{HashMap, VecDeque}; use tokio::time::{Duration, Instant}; use tracing::{debug, info, warn}; -use common::prelude::{OrderStatus, OrderType}; +use common::prelude::{OrderStatus, OrderType, Order, OrderSide}; use crate::config::{ExecutionAlgorithm, ExecutionConfig}; use crate::microstructure::{MicrostructureAnalyzer, OrderLevel, Trade}; @@ -45,44 +45,9 @@ pub struct OrderManager { next_order_id: u64, } -/// Order representation -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Order { - /// Unique order ID - pub id: String, - /// Parent strategy order ID - pub parent_id: Option, - /// Trading symbol - pub symbol: String, - /// Order side (Buy/Sell) - pub side: OrderSide, - /// Order type - pub order_type: OrderType, - /// Order quantity - pub quantity: f64, - /// Remaining quantity - pub remaining_quantity: f64, - /// Order price (for limit orders) - pub price: Option, - /// Order status - pub status: OrderStatus, - /// Time in force - pub time_in_force: TimeInForce, - /// Creation timestamp - pub created_at: chrono::DateTime, - /// Last update timestamp - pub updated_at: chrono::DateTime, - /// Execution algorithm used - pub execution_algorithm: String, - /// Execution parameters - pub execution_params: HashMap, -} +// Order struct removed - using canonical definition from common::prelude::Order -/// Order side -// OrderSide now imported from canonical source -use common::prelude::OrderSide; - -// OrderType and OrderStatus imported from canonical source in common::prelude +// OrderSide, OrderType and OrderStatus imported from canonical source in common::prelude /// Time in force #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/common/src/lib.rs b/common/src/lib.rs index 18241bc53..37c36f3ca 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -46,16 +46,16 @@ pub mod prelude { // Re-export constants pub use crate::constants::{DEFAULT_POOL_SIZE, MAX_QUERY_TIMEOUT_MS, SERVICE_DEFAULTS}; - // Re-export common types + // Re-export common types - CANONICAL ORDER INCLUDED pub use crate::types::{ ConfigVersion, ServiceId, ServiceStatus, RequestId, ConnectionInfo, ResourceLimits, Order, Position, Execution, Price, Quantity, Volume, Symbol, OrderId, TradeId, AccountId, - HftTimestamp, GenericTimestamp, Money + HftTimestamp, GenericTimestamp, Money, OrderType, OrderStatus, OrderSide, TimeInForce, + Currency, CommonTypeError }; - // Re-export trading types + // Re-export trading types (excluding duplicates already in types module) pub use crate::trading::{ - BookAction, Currency, MarketRegime, OrderSide, OrderStatus, OrderType, - Side, TickType, TimeInForce, + BookAction, MarketRegime, Side, TickType, }; } diff --git a/common/src/types.rs b/common/src/types.rs index d8a7ae797..c896a6dd7 100644 --- a/common/src/types.rs +++ b/common/src/types.rs @@ -817,89 +817,97 @@ impl Default for TimeInForce { // CORE TRADING TYPES - MIGRATED FROM TRADING_ENGINE // ============================================================================= -/// Represents a trading order in the system - CANONICAL DEFINITION -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +/// Canonical Order struct - UNIFIED DEFINITION based on Agent 1's comprehensive analysis +/// This represents the single source of truth for Order across all services +#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)] pub struct Order { - /// Unique order identifier - pub id: Uuid, - - /// Trading symbol (e.g., "EURUSD", "BTCUSD") - pub symbol: String, - - /// Order side (Buy or Sell) - pub side: OrderSide, - - /// Order quantity - pub quantity: Decimal, - - /// Order price (None for market orders) - pub price: Option, - - /// Order type - pub order_type: OrderType, - - /// Current order status - pub status: OrderStatus, - - /// Filled quantity - pub filled_quantity: Decimal, - - /// Remaining quantity - pub remaining_quantity: Decimal, - - /// Average fill price - pub avg_fill_price: Option, - - /// Order creation timestamp - pub created_at: DateTime, - - /// Last update timestamp - pub updated_at: DateTime, - - /// Order expiration timestamp (if applicable) - pub expires_at: Option>, - - /// Client order ID for tracking + // Core Identity + pub id: OrderId, pub client_order_id: Option, - - /// Broker-specific order ID pub broker_order_id: Option, + pub account_id: Option, - /// Stop loss price (if applicable) - pub stop_loss: Option, + // Trading Details + pub symbol: Symbol, + pub side: OrderSide, + pub order_type: OrderType, + pub status: OrderStatus, + pub time_in_force: TimeInForce, - /// Take profit price (if applicable) - pub take_profit: Option, + // Quantities & Pricing + pub quantity: Quantity, + pub price: Option, + pub stop_price: Option, + pub filled_quantity: Quantity, + pub remaining_quantity: Quantity, + pub average_price: Option, + + // Strategy Fields (from Agent 1) + pub parent_id: Option, + pub execution_algorithm: Option, + pub execution_params: std::collections::HashMap, + + // Risk Management (from Agent 1) + pub stop_loss: Option, + pub take_profit: Option, + + // Timestamps + pub created_at: HftTimestamp, + pub updated_at: Option, + pub expires_at: Option, + + // Extensibility + pub metadata: std::collections::HashMap, } impl Order { - /// Create a new order + /// Create a new order with canonical fields pub fn new( - symbol: String, + symbol: Symbol, side: OrderSide, - quantity: Decimal, - price: Option, + quantity: Quantity, + price: Option, order_type: OrderType, ) -> Self { - let now = Utc::now(); + let now = HftTimestamp::now_or_zero(); Self { - id: Uuid::new_v4(), - symbol, - side, - quantity, - price, - order_type, - status: OrderStatus::Pending, - filled_quantity: Decimal::ZERO, - remaining_quantity: quantity, - avg_fill_price: None, - created_at: now, - updated_at: now, - expires_at: None, + // Core Identity + id: OrderId::new(), client_order_id: None, broker_order_id: None, + account_id: None, + + // Trading Details + symbol, + side, + order_type, + status: OrderStatus::Created, + time_in_force: TimeInForce::default(), + + // Quantities & Pricing + quantity, + price, + stop_price: None, + filled_quantity: Quantity::ZERO, + remaining_quantity: quantity, + average_price: None, + + // Strategy Fields + parent_id: None, + execution_algorithm: None, + execution_params: std::collections::HashMap::new(), + + // Risk Management stop_loss: None, take_profit: None, + + // Timestamps + created_at: now, + updated_at: None, + expires_at: None, + + // Extensibility + metadata: std::collections::HashMap::new(), } } @@ -910,17 +918,109 @@ impl Order { /// Check if the order is partially filled pub fn is_partially_filled(&self) -> bool { - self.filled_quantity > Decimal::ZERO && self.filled_quantity < self.quantity + self.filled_quantity > Quantity::ZERO && self.filled_quantity < self.quantity } /// Calculate fill percentage - pub fn fill_percentage(&self) -> Decimal { + pub fn fill_percentage(&self) -> f64 { if self.quantity.is_zero() { - Decimal::ZERO + 0.0 } else { - self.filled_quantity / self.quantity * Decimal::from(100) + (self.filled_quantity.to_f64() / self.quantity.to_f64()) * 100.0 } } + + /// Set client order ID for tracking + pub fn with_client_order_id(mut self, client_order_id: String) -> Self { + self.client_order_id = Some(client_order_id); + self + } + + /// Set account ID + pub fn with_account_id(mut self, account_id: String) -> Self { + self.account_id = Some(account_id); + self + } + + /// Set time in force + pub fn with_time_in_force(mut self, time_in_force: TimeInForce) -> Self { + self.time_in_force = time_in_force; + self + } + + /// Set stop price + pub fn with_stop_price(mut self, stop_price: Price) -> Self { + self.stop_price = Some(stop_price); + self + } + + /// Set execution algorithm + pub fn with_execution_algorithm(mut self, algorithm: String) -> Self { + self.execution_algorithm = Some(algorithm); + self + } + + /// Add execution parameter + pub fn with_execution_param(mut self, key: String, value: f64) -> Self { + self.execution_params.insert(key, value); + self + } + + /// Set stop loss + pub fn with_stop_loss(mut self, stop_loss: Price) -> Self { + self.stop_loss = Some(stop_loss); + self + } + + /// Set take profit + pub fn with_take_profit(mut self, take_profit: Price) -> Self { + self.take_profit = Some(take_profit); + self + } + + /// Add metadata + pub fn with_metadata(mut self, key: String, value: String) -> Self { + self.metadata.insert(key, value); + self + } + + /// Update order status and timestamp + pub fn update_status(&mut self, status: OrderStatus) { + self.status = status; + self.updated_at = Some(HftTimestamp::now_or_zero()); + } + + /// Fill order with given quantity and price + pub fn fill(&mut self, fill_quantity: Quantity, fill_price: Price) -> Result<(), CommonTypeError> { + if self.filled_quantity + fill_quantity > self.quantity { + return Err(CommonTypeError::ValidationError { + field: "fill_quantity".to_string(), + reason: "Fill quantity exceeds remaining quantity".to_string(), + }); + } + + // Update filled quantity + let previous_filled = self.filled_quantity; + self.filled_quantity = self.filled_quantity + fill_quantity; + self.remaining_quantity = self.quantity - self.filled_quantity; + + // Update average price + if let Some(avg_price) = self.average_price { + let total_value = avg_price.to_f64() * previous_filled.to_f64() + fill_price.to_f64() * fill_quantity.to_f64(); + self.average_price = Some(Price::from_f64(total_value / self.filled_quantity.to_f64()).unwrap_or(fill_price)); + } else { + self.average_price = Some(fill_price); + } + + // Update status + if self.is_filled() { + self.update_status(OrderStatus::Filled); + } else { + self.update_status(OrderStatus::PartiallyFilled); + } + + Ok(()) + } } /// Represents a trading position - CANONICAL DEFINITION diff --git a/risk/src/safety/position_limiter.rs b/risk/src/safety/position_limiter.rs index 9d987302b..28ab49760 100644 --- a/risk/src/safety/position_limiter.rs +++ b/risk/src/safety/position_limiter.rs @@ -18,20 +18,9 @@ use crate::kelly_sizing::KellySizer; use crate::position_tracker::PositionTracker; use crate::safety::PositionLimiterConfig; use config::KellyConfig; -// Use common::types::prelude for Symbol +// Use common::types::prelude for Symbol and Order use crate::compliance::PositionLimit; - -// Production OrderRequest structure -#[derive(Debug, Clone)] -pub struct OrderRequest { - pub id: String, - pub symbol: Symbol, - pub account_id: String, - pub side: String, - pub quantity: f64, - pub price: Option, - pub order_type: String, -} +use common::types::Order; // Production HybridPositionLimiter implementation pub struct HybridPositionLimiter { @@ -90,23 +79,23 @@ impl HybridPositionLimiter { } } - pub async fn check_and_update(&self, order: &OrderRequest) -> Result<(), RiskError> { + pub async fn check_and_update(&self, order: &Order) -> Result<(), RiskError> { // Get current portfolio value for Kelly sizing + let account_id = order.account_id.as_ref().unwrap_or(&"default".to_string()); let portfolio_value = self - .get_portfolio_value(&order.account_id) + .get_portfolio_value(account_id) .await .unwrap_or_else(|| Price::from_f64(100000.0).unwrap_or(Price::ZERO)); - + // Calculate Kelly-based position size let kelly_position_size = self.kelly_sizer.get_position_size( &order.symbol, - &order.order_type, // Use order type as strategy identifier + &format!("{:?}", order.order_type), // Use order type as strategy identifier portfolio_value, - Price::from_f64(order.price.unwrap_or(100.0)) - .unwrap_or_else(|_| Price::from_f64(100.0).unwrap_or(Price::ONE)), + order.price.unwrap_or_else(|| Price::from_f64(100.0).unwrap_or(Price::ONE)), )?; - - let requested_position = Price::from_f64(order.quantity).unwrap_or(Price::ZERO); + + let requested_position = order.quantity.into(); // Check if requested position exceeds Kelly recommendation let kelly_limit = (kelly_position_size * 2.0)?; @@ -277,20 +266,18 @@ mod tests { } } - fn create_test_order() -> OrderRequest { + fn create_test_order() -> Order { // DYNAMIC: Use portfolio-based position sizing instead of hardcoded quantity let test_portfolio_value = 1_000_000.0; // $1M test portfolio let test_quantity = test_portfolio_value * 0.01 / 150.0; // 1% of portfolio at $150/share - - OrderRequest { - id: "order_001".to_string(), - symbol: Symbol::from("AAPL"), - account_id: "account_001".to_string(), - side: "BUY".to_string(), - quantity: test_quantity, - price: Some(150.0), - order_type: "LIMIT".to_string(), - } + + Order::new( + Symbol::from("AAPL"), + OrderSide::Buy, + Quantity::from_f64(test_quantity).unwrap_or(Quantity::ZERO), + Some(Price::from_f64(150.0).unwrap_or(Price::ONE)), + ).with_account_id("account_001".to_string()) + .with_order_type(OrderType::Limit) } #[tokio::test] diff --git a/tests/benches/small_batch_performance.rs b/tests/benches/small_batch_performance.rs index 4c70998dd..f217680d8 100644 --- a/tests/benches/small_batch_performance.rs +++ b/tests/benches/small_batch_performance.rs @@ -211,9 +211,9 @@ fn benchmark_simd_optimizations(c: &mut Criterion) { group.bench_function("array_of_structures", |b| { // Use canonical Order types from common module use common::types::{OrderId, OrderSide, OrderType}; - + #[derive(Clone, Copy)] - struct Order { + struct BenchOrder { order_id: u64, symbol_hash: u64, side: u8, @@ -230,10 +230,10 @@ fn benchmark_simd_optimizations(c: &mut Criterion) { let start = Instant::now(); let mut orders = Vec::with_capacity(8); - + // Add orders in AoS layout for j in 0..8 { - orders.push(Order { + orders.push(BenchOrder { order_id: j as u64, symbol_hash: 0x123456 + j as u64, side: j % 2, diff --git a/tests/integration/broker_risk_integration.rs b/tests/integration/broker_risk_integration.rs index 3cc68b04a..0b51586e2 100644 --- a/tests/integration/broker_risk_integration.rs +++ b/tests/integration/broker_risk_integration.rs @@ -197,18 +197,8 @@ pub struct RiskAssessment { pub validation_latency_ns: u64, } -// Use canonical Order types from common module -use common::types::{OrderSide, OrderType}; - -#[derive(Debug, Clone)] -pub struct Order { - pub symbol: String, - pub side: OrderSide, - pub quantity: Decimal, - pub price: Decimal, - pub order_type: OrderType, - pub timestamp: HardwareTimestamp, -} +// Use canonical Order from common module +use common::types::{Order, OrderSide, OrderType}; #[derive(Debug, Clone)] pub struct Position { diff --git a/tests/integration/end_to_end_trading.rs b/tests/integration/end_to_end_trading.rs index ce63af35b..482f09bf9 100644 --- a/tests/integration/end_to_end_trading.rs +++ b/tests/integration/end_to_end_trading.rs @@ -500,19 +500,8 @@ impl OrderExecutionEngine { } } -// Use canonical Order types from common module -use common::types::{OrderId, OrderSide, OrderType}; - -#[derive(Debug, Clone)] -pub struct Order { - pub order_id: String, - pub symbol: String, - pub side: OrderSide, - pub quantity: Decimal, - pub price: Decimal, - pub order_type: OrderType, - pub timestamp: HardwareTimestamp, -} +// Use canonical Order from common module +use common::types::{Order, OrderId, OrderSide, OrderType}; #[derive(Debug, Clone)] pub struct TradeExecution { diff --git a/tli/Cargo.toml b/tli/Cargo.toml index bf32aef26..df27b62e4 100644 --- a/tli/Cargo.toml +++ b/tli/Cargo.toml @@ -47,6 +47,9 @@ futures-util.workspace = true # Core types from trading engine (for canonical event types) trading_engine.workspace = true +# Canonical types from common crate +common.workspace = true + # Note: Database-related imports removed to enforce clean service architecture # - SQLite pools should only exist in services # - PostgreSQL connections should only exist in services diff --git a/tli/src/dashboard/events.rs b/tli/src/dashboard/events.rs index cd1984e24..70a0fb65b 100644 --- a/tli/src/dashboard/events.rs +++ b/tli/src/dashboard/events.rs @@ -122,17 +122,8 @@ pub struct ConfigurationEvent { pub changed_by: String, } -// Order Request -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct OrderRequest { - pub symbol: String, - pub side: OrderSide, - pub order_type: OrderType, - pub quantity: f64, - pub price: Option, - pub time_in_force: TimeInForce, - pub client_order_id: Option, -} +// Use canonical Order from common types +use common::types::Order as OrderRequest; // Configuration Update #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/trading_engine/src/brokers/icmarkets.rs b/trading_engine/src/brokers/icmarkets.rs index 0ec2eff2a..be2397ddd 100644 --- a/trading_engine/src/brokers/icmarkets.rs +++ b/trading_engine/src/brokers/icmarkets.rs @@ -3,7 +3,7 @@ //! Production-ready FIX connector for `ICMarkets` cTrader with real trading capabilities. use crate::trading::data_interface::{ - BrokerConnectionStatus, BrokerInterface, ExecutionReport, Position, + BrokerConnectionStatus, BrokerError, BrokerInterface, ExecutionReport, Position, }; use crate::trading_operations::TradingOrder; use crate::types::prelude::*; diff --git a/trading_engine/src/brokers/interactive_brokers.rs b/trading_engine/src/brokers/interactive_brokers.rs index 0ece48653..7a6fa7517 100644 --- a/trading_engine/src/brokers/interactive_brokers.rs +++ b/trading_engine/src/brokers/interactive_brokers.rs @@ -3,7 +3,7 @@ //! Simple stub implementation for compilation purposes. use crate::trading::data_interface::{ - BrokerConnectionStatus, BrokerInterface, ExecutionReport, Position, + BrokerConnectionStatus, BrokerError, BrokerInterface, ExecutionReport, Position, }; use crate::trading_operations::TradingOrder; use crate::types::prelude::*; diff --git a/trading_engine/src/features/unified_extractor.rs b/trading_engine/src/features/unified_extractor.rs index 718812ed6..1ec2e15e1 100644 --- a/trading_engine/src/features/unified_extractor.rs +++ b/trading_engine/src/features/unified_extractor.rs @@ -647,7 +647,7 @@ impl UnifiedFeatureExtractor { returns_1h, volatility_1h, volatility_4h, - volume: Volume(Decimal::from(latest.size.value())), + volume: Volume::new(Decimal::from(latest.size.value())), volume_ratio_1h, vwap_deviation, volume_imbalance, diff --git a/trading_engine/src/trading/position_manager.rs b/trading_engine/src/trading/position_manager.rs index 5c8bee5b7..b54b360c3 100644 --- a/trading_engine/src/trading/position_manager.rs +++ b/trading_engine/src/trading/position_manager.rs @@ -33,7 +33,7 @@ impl PositionManager { .entry(execution.symbol.clone()) .or_insert_with(|| Position { symbol: Symbol::new(execution.symbol.clone()), - quantity: Volume(Decimal::ZERO), + quantity: Volume::new(Decimal::ZERO), avg_cost: Price::ZERO, average_price: Price::ZERO, market_value: Price::ZERO, @@ -63,7 +63,7 @@ impl PositionManager { old_qty_decimal * old_cost_decimal + exec_qty_decimal * exec_price_decimal; let new_quantity_decimal = old_qty_decimal + exec_qty_decimal; - position.quantity = Volume(new_quantity_decimal); + position.quantity = Volume::new(new_quantity_decimal); position.avg_cost = if new_quantity_decimal > Decimal::ZERO { Price::from_f64( (total_cost / new_quantity_decimal) @@ -86,7 +86,7 @@ impl PositionManager { position.realized_pnl = position.realized_pnl + realized_pnl; let new_quantity = old_qty_decimal + reduction; - position.quantity = Volume(new_quantity); + position.quantity = Volume::new(new_quantity); if new_quantity > Decimal::ZERO { // Flipped to long - remaining quantity at execution price @@ -109,7 +109,7 @@ impl PositionManager { position.realized_pnl = position.realized_pnl + realized_pnl; let new_quantity_decimal = old_qty_decimal - reduction; - position.quantity = Volume(new_quantity_decimal); + position.quantity = Volume::new(new_quantity_decimal); if new_quantity_decimal < Decimal::ZERO { // Flipped to short - remaining quantity at execution price @@ -123,7 +123,7 @@ impl PositionManager { + exec_qty_decimal * exec_price_decimal; let new_quantity_decimal = old_qty_decimal - exec_qty_decimal; - position.quantity = Volume(new_quantity_decimal); + position.quantity = Volume::new(new_quantity_decimal); position.avg_cost = if new_quantity_decimal < Decimal::ZERO { Price::from_f64( (total_cost / new_quantity_decimal.abs()) diff --git a/trading_engine/src/trading_operations.rs b/trading_engine/src/trading_operations.rs index 30ef06bc6..a53c14be1 100644 --- a/trading_engine/src/trading_operations.rs +++ b/trading_engine/src/trading_operations.rs @@ -284,7 +284,7 @@ pub struct TradingOrder { } // OrderType ELIMINATED - Use canonical from types::prelude -pub use crate::types::prelude::OrderType; +// OrderType already imported above // OrderStatus ELIMINATED - Use canonical from types::prelude // All order types now use canonical definitions from types::basic diff --git a/trading_engine/src/types/basic.rs b/trading_engine/src/types/basic.rs index 7825c000d..468ee4228 100644 --- a/trading_engine/src/types/basic.rs +++ b/trading_engine/src/types/basic.rs @@ -14,8 +14,10 @@ use crate::types::errors::FoxhuntError; use std::fmt; use std::error::Error; +// Import canonical Order from common crate +use common::types::Order; + // Re-export canonical trading types from common crate -// ORDER TYPES DEFINED LOCALLY BELOW TO AVOID CIRCULAR DEPENDENCIES /// `TradingError` - Bridge type that provides static methods for creating `FoxhuntError` instances /// This maintains backward compatibility with existing code while using the unified error system. #[derive(Debug, Clone, PartialEq)] @@ -116,12 +118,14 @@ impl TradingError { // Note: Decimal and FromPrimitive are re-exported in prelude for services use crate::types::financial::{Decimal, FromPrimitive}; use chrono::{DateTime, Utc}; +use common::prelude::{Currency, Price, Side, TimeInForce, Volume}; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::time::{SystemTime, UNIX_EPOCH}; use std::{convert::TryFrom, str::FromStr}; use std::{ env, + iter::Sum, num::ParseIntError, ops::{Add, Div, Mul, Sub}, }; @@ -867,7 +871,7 @@ impl fmt::Display for MarketRegime { } } -impl FromStr for Currency { +impl FromStr for common::prelude::Currency { type Err = String; fn from_str(s: &str) -> Result { @@ -1000,10 +1004,10 @@ impl Default for Symbol { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Position { pub symbol: Symbol, - pub quantity: Volume, - pub avg_cost: Price, - pub average_price: Price, - pub market_value: Price, + pub quantity: common::prelude::Volume, + pub avg_cost: common::prelude::Price, + pub average_price: common::prelude::Price, + pub market_value: common::prelude::Price, pub unrealized_pnl: Decimal, pub realized_pnl: Decimal, pub last_updated: DateTime, @@ -1014,17 +1018,17 @@ pub struct Position { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub struct Money { pub amount: Decimal, - pub currency: Currency, + pub currency: common::prelude::Currency, } impl Money { #[must_use] - pub const fn new(amount: Decimal, currency: Currency) -> Self { + pub const fn new(amount: Decimal, currency: common::prelude::Currency) -> Self { Self { amount, currency } } #[must_use] - pub fn from_f64(amount: f64, currency: Currency) -> Self { + pub fn from_f64(amount: f64, currency: common::prelude::Currency) -> Self { Self { amount: Decimal::from_f64(amount).unwrap_or_else(|| { tracing::warn!("Failed to convert f64 {} to Decimal, using ZERO", amount); @@ -1201,9 +1205,9 @@ impl From<&str> for OrderId { pub struct Trade { pub trade_id: TradeId, pub symbol: Symbol, - pub side: Side, + pub side: common::prelude::Side, pub quantity: Quantity, - pub price: Price, + pub price: common::prelude::Price, pub timestamp: DateTime, } @@ -1215,27 +1219,7 @@ pub struct OrderBookLevel { pub count: u32, } -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Order { - pub id: OrderId, - pub order_id: OrderId, - pub client_order_id: String, - pub broker_order_id: Option, - pub account_id: String, - pub symbol: Symbol, - pub side: Side, - pub order_type: OrderType, - pub quantity: Quantity, - pub price: Option, - pub stop_price: Option, - pub filled_quantity: Quantity, - pub remaining_quantity: Quantity, - pub average_price: Option, - pub time_in_force: TimeInForce, - pub status: OrderStatus, - pub timestamp: DateTime, - pub created_at: DateTime, -} +// Order struct removed - using canonical definition from common::types::Order #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Fill { @@ -1246,7 +1230,7 @@ pub struct Fill { pub quantity: Quantity, pub price: Price, pub timestamp: DateTime, - pub commission: Option, + pub commission: Option, pub trade_id: Option, } @@ -1275,7 +1259,7 @@ impl MarketTick { /// Create a new market tick with current timestamp pub fn new( symbol: Symbol, - price: Price, + price: common::prelude::Price, size: Quantity, tick_type: TickType, exchange: String, @@ -2237,7 +2221,7 @@ pub struct TradingSignal { /// Signal strength (-1.0 to 1.0) pub strength: f64, /// Signal direction - pub direction: Side, + pub direction: common::prelude::Side, /// Confidence level (0.0 to 1.0) pub confidence: f64, /// Signal generation timestamp @@ -2253,7 +2237,7 @@ impl TradingSignal { pub fn new( symbol: Symbol, strength: f64, - direction: Side, + direction: common::prelude::Side, confidence: f64, source: String, ) -> Result { @@ -2469,7 +2453,7 @@ pub enum ExecutionStatus { /// Quantity filled so far filled_quantity: Quantity, /// Average fill price - average_price: Price, + average_price: common::prelude::Price, }, /// Order completely filled Filled { @@ -2500,11 +2484,11 @@ impl Order { #[must_use] pub fn new( symbol: Symbol, - side: Side, + side: common::prelude::Side, order_type: OrderType, quantity: Quantity, - price: Option, - time_in_force: TimeInForce, + price: Option, + time_in_force: common::prelude::TimeInForce, ) -> Self { let order_id = OrderId::new(); let now = Utc::now(); @@ -2545,27 +2529,27 @@ impl Order { /// Create a limit order #[must_use] - pub fn limit(symbol: Symbol, side: Side, quantity: Quantity, price: Price) -> Self { + pub fn limit(symbol: Symbol, side: common::prelude::Side, quantity: Quantity, price: common::prelude::Price) -> Self { Self::new( symbol, side, OrderType::Limit, quantity, Some(price), - TimeInForce::Day, + common::prelude::TimeInForce::Day, ) } /// Create a market order #[must_use] - pub fn market(symbol: Symbol, side: Side, quantity: Quantity) -> Self { + pub fn market(symbol: Symbol, side: common::prelude::Side, quantity: Quantity) -> Self { Self::new( symbol, side, OrderType::Market, quantity, None, - TimeInForce::IOC, + common::prelude::TimeInForce::IOC, ) } @@ -2704,7 +2688,7 @@ impl OrderRef { /// Create a limit order reference #[must_use] - pub fn limit(symbol_hash: u64, side: Side, quantity: u64, price: u64) -> Self { + pub fn limit(symbol_hash: u64, side: common::prelude::Side, quantity: u64, price: u64) -> Self { Self { id: OrderId::new().value(), symbol_hash, @@ -2718,7 +2702,7 @@ impl OrderRef { /// Create a market order reference #[must_use] - pub fn market(symbol_hash: u64, side: Side, quantity: u64) -> Self { + pub fn market(symbol_hash: u64, side: common::prelude::Side, quantity: u64) -> Self { Self { id: OrderId::new().value(), symbol_hash, @@ -2748,24 +2732,24 @@ impl OrderRef { /// Get price as Price type (None for market orders) #[must_use] - pub const fn get_price(&self) -> Option { + pub const fn get_price(&self) -> Option { if self.price == 0 { None } else { - Some(Price::from_raw(self.price)) + Some(common::prelude::Price::from_raw(self.price)) } } /// Check if this is a buy order #[must_use] pub fn is_buy(&self) -> bool { - self.side == Side::Buy + self.side == common::prelude::Side::Buy } /// Check if this is a sell order #[must_use] pub fn is_sell(&self) -> bool { - self.side == Side::Sell + self.side == common::prelude::Side::Sell } /// Check if this is a market order @@ -2786,7 +2770,7 @@ impl Default for OrderRef { Self { id: 0, symbol_hash: 0, - side: Side::Buy, + side: common::prelude::Side::Buy, order_type: OrderType::Market, quantity: 0, price: 0, @@ -2880,13 +2864,13 @@ pub struct ExecutionReport { /// Executed quantity for this report pub executed_quantity: Option, /// Execution price for this report - pub execution_price: Option, + pub execution_price: Option, /// Cumulative filled quantity (for backward compatibility) pub filled_quantity: Quantity, /// Cumulative filled quantity pub cumulative_quantity: Quantity, /// Average fill price - pub average_price: Option, + pub average_price: Option, /// Remaining quantity pub remaining_quantity: Quantity, /// Execution timestamp @@ -2973,7 +2957,7 @@ impl ExecutionReport { broker_order_id: String, status: ExecutionStatus, symbol: Symbol, - side: Side, + side: common::prelude::Side, quantity: Quantity, broker_name: String, execution_id: String, @@ -3002,7 +2986,7 @@ impl ExecutionReport { /// Update with execution details #[must_use] - pub fn with_execution(mut self, executed_quantity: Quantity, execution_price: Price) -> Self { + pub fn with_execution(mut self, executed_quantity: Quantity, execution_price: common::prelude::Price) -> Self { self.executed_quantity = Some(executed_quantity); self.execution_price = Some(execution_price); self.cumulative_quantity = self.cumulative_quantity + executed_quantity; diff --git a/trading_engine/src/types/mod.rs b/trading_engine/src/types/mod.rs index 16149ea9b..3941218b4 100644 --- a/trading_engine/src/types/mod.rs +++ b/trading_engine/src/types/mod.rs @@ -46,6 +46,18 @@ pub mod metrics; /// Trading engine type registry for dynamic type management pub mod type_registry; +/// Trading engine error types +pub mod errors; + +/// Trading engine financial types +pub mod financial; + +/// Trading engine validation utilities +pub mod validation; + +/// Prelude module for convenient imports +pub mod prelude; + // REMOVED: Service prelude - eliminated anti-pattern, use common::types::* instead // ============================================================================ @@ -77,6 +89,12 @@ pub enum TradingEngineError { pub use basic::*; pub use metrics::*; pub use type_registry::*; +pub use errors::*; +pub use financial::*; +pub use validation::*; + +// Re-export prelude for convenient access +pub use prelude::*; #[cfg(test)] mod tests { diff --git a/trading_engine/src/types/prelude.rs b/trading_engine/src/types/prelude.rs new file mode 100644 index 000000000..b6a8f83df --- /dev/null +++ b/trading_engine/src/types/prelude.rs @@ -0,0 +1,19 @@ +//! Trading Engine Types Prelude +//! +//! This module re-exports commonly used types from both the trading engine +//! and the common crate for convenient access. + +// Re-export from common crate (canonical types) +pub use common::prelude::*; +pub use common::types::*; + +// Re-export trading engine specific types +pub use crate::types::{ + basic::*, + metrics::*, + type_registry::*, + errors::*, + financial::*, + validation::*, + TradingEngineError, +}; \ No newline at end of file diff --git a/trading_engine/src/types/type_registry.rs b/trading_engine/src/types/type_registry.rs index 00a103408..bf61cc761 100644 --- a/trading_engine/src/types/type_registry.rs +++ b/trading_engine/src/types/type_registry.rs @@ -10,8 +10,8 @@ /// This compile-time registry ensures that all types are imported from their /// canonical locations. Any attempt to duplicate types will be caught at compile time. pub mod canonical_types { - // Re-export all canonical types from their single source of truth location - pub use crate::types::basic::{ + // Re-export all canonical types from common crate (single source of truth) + pub use common::types::{ AccountId, AggregateId, AggregateVersion, @@ -157,47 +157,47 @@ impl std::fmt::Display for ViolationType { impl std::error::Error for TypeViolation {} // Implement CanonicalType for all core types -impl CanonicalType for crate::basic::Price { +impl CanonicalType for crate::types::basic::Price { const CANONICAL_PATH: &'static str = "types::basic::Price"; const TYPE_NAME: &'static str = "Price"; } -impl CanonicalType for crate::basic::Quantity { +impl CanonicalType for crate::types::basic::Quantity { const CANONICAL_PATH: &'static str = "types::basic::Quantity"; const TYPE_NAME: &'static str = "Quantity"; } -impl CanonicalType for crate::basic::Volume { +impl CanonicalType for crate::types::basic::Volume { const CANONICAL_PATH: &'static str = "types::basic::Volume"; const TYPE_NAME: &'static str = "Volume"; } -impl CanonicalType for crate::basic::Symbol { +impl CanonicalType for crate::types::basic::Symbol { const CANONICAL_PATH: &'static str = "types::basic::Symbol"; const TYPE_NAME: &'static str = "Symbol"; } -impl CanonicalType for crate::basic::AssetId { +impl CanonicalType for crate::types::basic::AssetId { const CANONICAL_PATH: &'static str = "types::basic::AssetId"; const TYPE_NAME: &'static str = "AssetId"; } -impl CanonicalType for crate::basic::Side { +impl CanonicalType for crate::types::basic::Side { const CANONICAL_PATH: &'static str = "types::basic::Side"; const TYPE_NAME: &'static str = "Side"; } -impl CanonicalType for crate::basic::OrderType { +impl CanonicalType for crate::types::basic::OrderType { const CANONICAL_PATH: &'static str = "types::basic::OrderType"; const TYPE_NAME: &'static str = "OrderType"; } -impl CanonicalType for crate::basic::OrderId { +impl CanonicalType for crate::types::basic::OrderId { const CANONICAL_PATH: &'static str = "types::basic::OrderId"; const TYPE_NAME: &'static str = "OrderId"; } -impl CanonicalType for crate::basic::Order { +impl CanonicalType for crate::types::basic::Order { const CANONICAL_PATH: &'static str = "types::basic::Order"; const TYPE_NAME: &'static str = "Order"; }