//! Position builder for testing use chrono::{DateTime, Utc}; /// Mock position for testing #[derive(Clone, Debug)] pub struct MockPosition { pub symbol: String, pub quantity: f64, pub entry_price: f64, pub current_price: f64, pub timestamp: DateTime, } impl MockPosition { pub fn pnl(&self) -> f64 { (self.current_price - self.entry_price) * self.quantity } pub fn pnl_percent(&self) -> f64 { ((self.current_price - self.entry_price) / self.entry_price) * 100.0 } } /// Builder for creating mock positions pub struct PositionBuilder { symbol: String, quantity: f64, entry_price: f64, current_price: f64, timestamp: DateTime, } impl PositionBuilder { pub fn new() -> Self { Self { symbol: "AAPL".to_string(), quantity: 100.0, entry_price: 150.0, current_price: 150.0, timestamp: Utc::now(), } } pub fn symbol(mut self, symbol: &str) -> Self { self.symbol = symbol.to_string(); self } pub fn long(mut self, quantity: f64) -> Self { self.quantity = quantity.abs(); self } pub fn short(mut self, quantity: f64) -> Self { self.quantity = -quantity.abs(); self } pub fn entry_price(mut self, price: f64) -> Self { self.entry_price = price; self } pub fn current_price(mut self, price: f64) -> Self { self.current_price = price; self } pub fn profitable(mut self, percent: f64) -> Self { self.current_price = self.entry_price * (1.0 + percent / 100.0); self } pub fn losing(mut self, percent: f64) -> Self { self.current_price = self.entry_price * (1.0 - percent / 100.0); self } pub fn build(self) -> MockPosition { MockPosition { symbol: self.symbol, quantity: self.quantity, entry_price: self.entry_price, current_price: self.current_price, timestamp: self.timestamp, } } } impl Default for PositionBuilder { fn default() -> Self { Self::new() } } #[cfg(test)] mod tests { use super::*; #[test] fn test_position_builder() { let pos = PositionBuilder::new() .symbol("TSLA") .long(50.0) .entry_price(200.0) .current_price(220.0) .build(); assert_eq!(pos.symbol, "TSLA"); assert_eq!(pos.quantity, 50.0); assert_eq!(pos.pnl(), 1000.0); // (220 - 200) * 50 assert_eq!(pos.pnl_percent(), 10.0); } #[test] fn test_short_position() { let pos = PositionBuilder::new() .short(100.0) .entry_price(150.0) .current_price(140.0) .build(); assert!(pos.quantity < 0.0); assert_eq!(pos.pnl(), -1000.0); // (140 - 150) * -100 } #[test] fn test_profitable_position() { let pos = PositionBuilder::new() .entry_price(100.0) .profitable(10.0) .build(); assert_eq!(pos.current_price, 110.0); assert_eq!(pos.pnl_percent(), 10.0); } #[test] fn test_losing_position() { let pos = PositionBuilder::new() .entry_price(100.0) .losing(5.0) .build(); assert_eq!(pos.current_price, 95.0); assert_eq!(pos.pnl_percent(), -5.0); } }