use chrono::NaiveDate; use fidc_core::{ CnSmallCapRotationConfig, CnSmallCapRotationStrategy, DataSet, JqMicroCapConfig, JqMicroCapStrategy, PortfolioState, Strategy, StrategyContext, }; use std::collections::BTreeSet; use std::path::PathBuf; #[test] fn strategy_emits_target_weights_and_diagnostics() { let data_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../data/demo"); let data = DataSet::from_csv_dir(&data_dir).expect("demo data"); let decision_date = NaiveDate::from_ymd_opt(2024, 1, 10).unwrap(); let execution_date = NaiveDate::from_ymd_opt(2024, 1, 11).unwrap(); let portfolio = PortfolioState::new(1_000_000.0); let mut cfg = CnSmallCapRotationConfig::cn_dyn_smallcap_band(); cfg.signal_symbol = Some("000001.SZ".to_string()); cfg.short_ma_days = 3; cfg.long_ma_days = 5; let mut strategy = CnSmallCapRotationStrategy::new(cfg); let subscriptions = BTreeSet::new(); let decision = strategy .on_day(&StrategyContext { execution_date, decision_date, decision_index: 0, data: &data, portfolio: &portfolio, futures_account: None, open_orders: &[], dynamic_universe: None, subscriptions: &subscriptions, process_events: &[], active_process_event: None, active_datetime: None, order_events: &[], fills: &[], }) .expect("decision"); assert!(decision.rebalance); assert!(decision.rebalance); assert!(!decision.diagnostics.is_empty()); assert!( decision .diagnostics .iter() .any(|line| line.contains("signal_symbol=")) ); assert_eq!(strategy.name(), "cn-dyn-smallcap-band"); } #[test] fn jq_strategy_emits_same_day_decision() { let data_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../data/demo"); let data = DataSet::from_csv_dir(&data_dir).expect("demo data"); let execution_date = NaiveDate::from_ymd_opt(2024, 1, 10).unwrap(); let portfolio = PortfolioState::new(1_000_000.0); let mut cfg = JqMicroCapConfig::jq_microcap(); cfg.benchmark_signal_symbol = "000001.SZ".to_string(); cfg.benchmark_short_ma_days = 3; cfg.benchmark_long_ma_days = 5; cfg.stock_short_ma_days = 3; cfg.stock_mid_ma_days = 4; cfg.stock_long_ma_days = 5; let mut strategy = JqMicroCapStrategy::new(cfg); let subscriptions = BTreeSet::new(); let decision = strategy .on_day(&StrategyContext { execution_date, decision_date: execution_date, decision_index: 0, data: &data, portfolio: &portfolio, futures_account: None, open_orders: &[], dynamic_universe: None, subscriptions: &subscriptions, process_events: &[], active_process_event: None, active_datetime: None, order_events: &[], fills: &[], }) .expect("jq decision"); assert!(!decision.rebalance); assert!( decision .diagnostics .iter() .any(|line| line.contains("jq_microcap signal=")) ); assert!( decision .diagnostics .iter() .any(|line| line.contains("selected=")) ); }