diff --git a/crates/fidc-core/src/broker.rs b/crates/fidc-core/src/broker.rs index 18156b1..ab1f0ac 100644 --- a/crates/fidc-core/src/broker.rs +++ b/crates/fidc-core/src/broker.rs @@ -5245,7 +5245,7 @@ where fn rebalance_valuation_price_field_name(&self) -> &'static str { if self.is_open_auction_matching() { - "prev_close" + "day_open" } else { price_field_name(self.execution_price_field) } @@ -5256,7 +5256,7 @@ where snapshot: &crate::data::DailyMarketSnapshot, ) -> Option { let price = if self.is_open_auction_matching() { - snapshot.prev_close + snapshot.price(PriceField::DayOpen) } else { snapshot.price(self.execution_price_field) }; @@ -7377,6 +7377,49 @@ mod tests { ); } + #[test] + fn target_portfolio_smart_open_auction_uses_day_open_for_valuation() { + let date = chrono::NaiveDate::from_ymd_opt(2025, 1, 2).expect("valid date"); + let mut snapshot = limit_test_snapshot(); + snapshot.day_open = 12.0; + snapshot.open = 12.0; + snapshot.last_price = 12.0; + snapshot.prev_close = 10.0; + snapshot.upper_limit = 20.0; + snapshot.lower_limit = 1.0; + let data = DataSet::from_components_with_actions_and_quotes( + vec![limit_test_instrument()], + vec![snapshot], + Vec::new(), + vec![limit_test_candidate(true, true)], + vec![limit_test_benchmark()], + Vec::new(), + Vec::new(), + ) + .expect("valid dataset"); + let broker = BrokerSimulator::new_with_execution_price( + ChinaAShareCostModel::default(), + ChinaEquityRuleHooks, + PriceField::DayOpen, + ) + .with_volume_limit(false) + .with_liquidity_limit(false) + .with_inactive_limit(false); + let portfolio = PortfolioState::new(20_000.0); + let mut target_weights = BTreeMap::new(); + target_weights.insert("000001.SZ".to_string(), 1.0); + + let (target_quantities, diagnostics) = broker + .target_quantities(date, &portfolio, &data, &target_weights) + .expect("target quantities"); + + assert_eq!( + target_quantities.get("000001.SZ").copied(), + Some(1_600), + "{diagnostics:?}" + ); + } + #[test] fn target_value_zero_rejects_sell_when_market_snapshot_missing() { let trade_date = chrono::NaiveDate::from_ymd_opt(2025, 1, 2).expect("valid date");