diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index c03da60..648b3cc 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -13981,6 +13981,40 @@ mod tests { assert_eq!(super::completed_session_factor_date(&ctx, prev, prev, None), None); } + #[test] + fn completed_session_bound_value_does_not_read_same_day_future_value() { + let prev = d(2025, 1, 2); + let curr = d(2025, 1, 3); + let symbol = "000001.SZ"; + let mut parts = single_symbol_platform_data(&[prev, curr], symbol).snapshot_components(); + for row in &mut parts.factors { + row.extra_factors.insert("native_daily".into(), if row.date == prev { 2.0 } else { 999.0 }); + row.extra_factors.insert("published_today".into(), 7.0); + } + let data = DataSet::from_components(parts.instruments, parts.market, parts.factors, + parts.candidates, parts.benchmarks).unwrap(); + let portfolio = PortfolioState::new(10_000.0); + let subscriptions = BTreeSet::new(); + let ctx = StrategyContext { + execution_date: curr, decision_date: curr, decision_index: 1, + 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: &[], + }; + let mut cfg = PlatformExprStrategyConfig::generic(); + cfg.stock_filter_expr = "native_daily > 0 && published_today > 0".to_string(); + cfg.completed_session_factor_fields.insert("native_daily".to_string()); + let strategy = PlatformExprStrategy::new(cfg); + let morning = strategy.stock_state_with_factor_date_and_time(&ctx, curr, curr, symbol, + NaiveTime::from_hms_opt(10, 0, 0), false).unwrap(); + assert_eq!(morning.extra_factors["native_daily"], 2.0); + assert_eq!(morning.extra_factors["published_today"], 7.0); + let close = strategy.stock_state_with_factor_date_and_time(&ctx, curr, curr, symbol, + NaiveTime::from_hms_opt(15, 0, 0), false).unwrap(); + assert_eq!(close.extra_factors["native_daily"], 999.0); + } + #[test] fn target_scale_replenishment_preserves_strategy_cash_allocation() { let scale = 30.0 / 31.0;