use std::collections::HashMap;
use chrono::{DateTime, FixedOffset, TimeZone, Utc};
use crate::unified_data::Position;
#[test]
fn test_position_basic_functionality() {
let now = Utc::now().with_timezone(&FixedOffset::east(0));
let mut position = Position::new("BTC", 1.0, 50000.0, 51000.0, now);
assert_eq!(position.symbol, "BTC");
assert_eq!(position.size, 1.0);
assert_eq!(position.entry_price, 50000.0);
assert_eq!(position.current_price, 51000.0);
assert_eq!(position.leverage, 1.0);
assert_eq!(position.liquidation_price, None);
assert_eq!(position.margin, None);
assert!(position.is_long());
assert!(!position.is_short());
assert!(!position.is_flat());
assert_eq!(position.unrealized_pnl, 1000.0);
position.update_price(52000.0);
assert_eq!(position.current_price, 52000.0);
assert_eq!(position.unrealized_pnl, 2000.0);
position.apply_funding_payment(100.0);
assert_eq!(position.funding_pnl, 100.0);
assert_eq!(position.total_pnl(), 2100.0); }
#[test]
fn test_position_direction_methods() {
let now = Utc::now().with_timezone(&FixedOffset::east(0));
let long_position = Position::new("BTC", 1.0, 50000.0, 51000.0, now);
assert!(long_position.is_long());
assert!(!long_position.is_short());
assert!(!long_position.is_flat());
let short_position = Position::new("ETH", -2.0, 3000.0, 2900.0, now);
assert!(!short_position.is_long());
assert!(short_position.is_short());
assert!(!short_position.is_flat());
let flat_position = Position::new("XRP", 0.0, 1.0, 1.0, now);
assert!(!flat_position.is_long());
assert!(!flat_position.is_short());
assert!(flat_position.is_flat());
}
#[test]
fn test_position_pnl_calculations() {
let now = Utc::now().with_timezone(&FixedOffset::east(0));
let mut position = Position::new("BTC", 1.0, 50000.0, 51000.0, now);
assert_eq!(position.unrealized_pnl, 1000.0);
assert_eq!(position.realized_pnl, 0.0);
assert_eq!(position.funding_pnl, 0.0);
assert_eq!(position.total_pnl(), 1000.0);
assert_eq!(position.notional_value(), 51000.0);
position.update_price(52000.0);
assert_eq!(position.unrealized_pnl, 2000.0);
assert_eq!(position.total_pnl(), 2000.0);
assert_eq!(position.notional_value(), 52000.0);
position.apply_funding_payment(100.0);
assert_eq!(position.funding_pnl, 100.0);
assert_eq!(position.total_pnl(), 2100.0);
position.apply_funding_payment(-50.0);
assert_eq!(position.funding_pnl, 50.0);
assert_eq!(position.total_pnl(), 2050.0);
let mut short_position = Position::new("ETH", -2.0, 3000.0, 2900.0, now);
assert_eq!(short_position.unrealized_pnl, 200.0); assert_eq!(short_position.notional_value(), 5800.0);
short_position.update_price(2800.0);
assert_eq!(short_position.unrealized_pnl, 400.0); assert_eq!(short_position.notional_value(), 5600.0);
short_position.apply_funding_payment(-75.0);
assert_eq!(short_position.funding_pnl, -75.0);
assert_eq!(short_position.total_pnl(), 325.0); }
#[test]
fn test_position_with_metadata() {
let now = Utc::now().with_timezone(&FixedOffset::east(0));
let mut position = Position::new("BTC", 1.0, 50000.0, 51000.0, now);
position.metadata.insert("strategy".to_string(), "sma_cross".to_string());
position.metadata.insert("entry_reason".to_string(), "momentum".to_string());
assert_eq!(position.metadata.get("strategy"), Some(&"sma_cross".to_string()));
assert_eq!(position.metadata.get("entry_reason"), Some(&"momentum".to_string()));
assert_eq!(position.metadata.get("nonexistent"), None);
position.metadata.insert("entry_reason".to_string(), "breakout".to_string());
assert_eq!(position.metadata.get("entry_reason"), Some(&"breakout".to_string()));
position.leverage = 5.0;
assert_eq!(position.leverage, 5.0);
}
#[test]
fn test_position_with_zero_size() {
let now = Utc::now().with_timezone(&FixedOffset::east(0));
let mut position = Position::new("BTC", 0.0, 50000.0, 51000.0, now);
assert_eq!(position.size, 0.0);
assert_eq!(position.unrealized_pnl, 0.0);
assert_eq!(position.notional_value(), 0.0);
assert!(position.is_flat());
position.update_price(52000.0);
assert_eq!(position.unrealized_pnl, 0.0);
position.apply_funding_payment(100.0);
assert_eq!(position.funding_pnl, 100.0);
assert_eq!(position.total_pnl(), 100.0);
}
#[test]
fn test_position_with_leverage_and_liquidation() {
let now = Utc::now().with_timezone(&FixedOffset::east(0));
let mut position = Position::new("BTC", 1.0, 50000.0, 51000.0, now);
position.leverage = 5.0;
position.liquidation_price = Some(45000.0);
position.margin = Some(10000.0);
assert_eq!(position.leverage, 5.0);
assert_eq!(position.liquidation_price, Some(45000.0));
assert_eq!(position.margin, Some(10000.0));
position.update_price(48000.0);
assert_eq!(position.unrealized_pnl, -2000.0);
assert!(position.current_price > position.liquidation_price.unwrap());
position.update_price(44000.0);
assert_eq!(position.unrealized_pnl, -6000.0);
assert!(position.current_price < position.liquidation_price.unwrap());
}