From c4632bacf1c4a84796eb46ce90ef90f738773a76 Mon Sep 17 00:00:00 2001 From: boris Date: Thu, 10 Sep 2026 14:08:05 +0800 Subject: [PATCH] =?UTF-8?q?=E7=8B=AC=E7=AB=8B=E4=BF=9D=E7=95=99=E5=B8=82?= =?UTF-8?q?=E5=9C=BA=E7=BB=9F=E8=AE=A1=E5=B9=B6=E6=A0=87=E6=98=8E=E8=A1=8C?= =?UTF-8?q?=E4=B8=9A=E7=BC=BA=E5=A4=B1=E6=97=A5=E6=9C=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/fidc-core/src/market_event_context.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/crates/fidc-core/src/market_event_context.rs b/crates/fidc-core/src/market_event_context.rs index e6a0d3d..32b7b51 100644 --- a/crates/fidc-core/src/market_event_context.rs +++ b/crates/fidc-core/src/market_event_context.rs @@ -67,6 +67,7 @@ pub struct OutputDay { pub no_limit: usize, pub profit_effect_members: Vec, pub profit_effect_missing: Vec, + pub industry_missing: Vec, } #[derive(Serialize)] @@ -193,8 +194,14 @@ pub fn aggregate(request: Request) -> Result { fields.insert("industry_rank".into(), ranks.get(name).copied()); fields.insert("industry_size".into(), Some(universe.len() as f64)); } + let industry_missing=members.iter().filter(|(_,group)|group.is_none()).map(|(s,_)|s.clone()).collect::>(); + if !industry_missing.is_empty() { + // An unclassified member may belong to any group; never silently shrink a group. + state.industry_history.clear(); + for fields in industries.values_mut() { for value in fields.values_mut() { *value=None; } } + } output.push(OutputDay { date:day.date, common, industries, members, securities:day.rows.len(), active, paused, - no_limit:unlimited, profit_effect_members:previous_ups, profit_effect_missing:profit_missing }); + no_limit:unlimited, profit_effect_members:previous_ups, profit_effect_missing:profit_missing, industry_missing }); state.last_date = Some(day.date); state.streaks = streaks; state.limit_ups = ups; } Ok(Output {contract:CONTRACT, days:output, state}) @@ -236,4 +243,13 @@ mod tests { let unknown=aggregate(Request{days:vec![day(1,true)],previous:State::default()}).unwrap(); assert_eq!(unknown.days[0].common["market_high_board"],None); } + #[test] + fn missing_industry_does_not_invent_groups_or_disable_independent_market_facts() { + let mut missing=day(2,true);missing.rows[0].industry=None; + let r=aggregate(Request{days:vec![day(1,false),missing,day(3,true)],previous:State::default()}).unwrap(); + assert_eq!(r.days[1].common["market_breadth"],Some(0.5)); + assert_eq!(r.days[1].industry_missing,vec!["A"]); + assert!(r.days[1].industries.values().flat_map(|g|g.values()).all(Option::is_none)); + assert_eq!(r.days[2].industries["I"]["industry_return_20"],None); + } }