//! Trading domain models for the trading-data repository layer //! //! This module provides access to the canonical trading domain models from the common crate. //! Instead of re-exporting types (which was removed per architectural cleanup), this module //! serves as documentation and testing for the domain models used by the repository layer. //! //! # Architecture Decision //! //! The trading-data crate follows the clean architecture pattern where: //! - **Common crate** contains canonical domain model definitions //! - **Repository layer** (this crate) provides data persistence patterns //! - **No re-exports** to avoid circular dependencies and maintain clear boundaries //! //! # Usage Pattern //! //! ```rust,no_run //! // Import domain models directly from common //! use common::types::{Order, Position, Execution, OrderSide, OrderStatus}; //! use trading_data::{OrderRepository, PostgresOrderRepository}; //! //! // Use with repository patterns //! # async fn example() -> Result<(), Box> { //! # let pool = sqlx::postgres::PgPool::connect("postgresql://...").await?; //! let repo = PostgresOrderRepository::new(pool); //! let orders = repo.find_by_status(OrderStatus::Filled).await?; //! # Ok(()) //! # } //! ``` //! //! # Domain Models //! //! The following domain models are used by this repository layer: //! //! ## Order Management //! - [`Order`] - Core order entity with lifecycle management //! - [`OrderSide`] - Buy/Sell enumeration //! - [`OrderType`] - Market/Limit/Stop order types //! - [`OrderStatus`] - Order state (Pending, Filled, Cancelled, etc.) //! //! ## Position Tracking //! - [`Position`] - Position entity with P&L calculations //! - Position-related calculations for risk management //! //! ## Execution Data //! - [`Execution`] - Trade execution records //! - Commission and fee tracking //! - Venue and counterparty information //! //! All model implementations are maintained in `common::types` for consistency //! across all services in the trading system. //! //! [`Order`]: common::types::Order //! [`OrderSide`]: common::types::OrderSide //! [`OrderType`]: common::types::OrderType //! [`OrderStatus`]: common::types::OrderStatus //! [`Position`]: common::types::Position //! [`Execution`]: common::types::Execution // Removed unused imports - keeping only what's needed // Removed direct rust_decimal imports - using common::Decimal via prelude // use rust_decimal_macros::dec; // Use common::dec! macro instead // REMOVED: All pub use statements eliminated per cleanup requirements // Use direct import: common::types::Order // Order, Position, and Execution are now imported from common::prelude // All implementations are maintained in the canonical location: common/src/types.rs // All order-related enums (OrderSide, OrderType, OrderStatus) are imported from common::prelude // Position is now imported from common::prelude // All implementations are maintained in the canonical location: common/src/types.rs // Execution is now imported from common::prelude // All implementations are maintained in the canonical location: common/src/types.rs #[cfg(test)] mod tests { use common::{ Execution, Order, OrderSide, OrderStatus, OrderType, Position, Price, Quantity, Symbol, }; use rust_decimal::Decimal; use rust_decimal_macros::dec; use uuid::Uuid; #[test] fn test_order_creation() { let order = Order::new( Symbol::new("EURUSD".to_string()), OrderSide::Buy, Quantity::from_decimal(dec!(100000)).unwrap(), Some(Price::from_decimal(dec!(1.1000))), OrderType::Limit, ); assert_eq!(order.symbol.as_ref(), "EURUSD"); assert_eq!(order.side, OrderSide::Buy); assert!((order.quantity.to_f64() - 100_000.0).abs() < 0.01); assert_eq!(order.status, OrderStatus::Created); assert!(!order.is_filled()); assert!(!order.is_partially_filled()); } #[test] fn test_position_pnl_calculation() { let mut position = Position::new("EURUSD".to_string(), dec!(100000), dec!(1.1000)); // Test long position with profit position.calculate_unrealized_pnl(dec!(1.1100)); assert_eq!(position.unrealized_pnl, dec!(1000)); assert!(position.is_long()); // Test ROI calculation let roi = position.roi_percentage(); assert!(roi > Decimal::ZERO); } #[test] fn test_execution_calculation() { let execution = Execution::new( Uuid::new_v4(), "EURUSD".to_string(), dec!(100000), dec!(1.1000), OrderSide::Buy, dec!(5.0), ); assert_eq!(execution.gross_value, dec!(110000)); // 100000 * 1.1000 assert_eq!(execution.net_value, dec!(110005.0)); // Buy: gross + fees let effective_price = execution.effective_price(); assert!(effective_price > execution.price); } #[test] fn test_order_status_checks() { // OrderStatus doesn't have is_terminal/is_active methods directly // These would need to be implemented on OrderStatus if needed // For now, just test the enum variants exist assert_eq!(OrderStatus::Filled, OrderStatus::Filled); assert_eq!(OrderStatus::Cancelled, OrderStatus::Cancelled); assert_eq!(OrderStatus::Submitted, OrderStatus::Submitted); } }