From 57aebe97ec0ee51c629e0ead41bc61052587457b Mon Sep 17 00:00:00 2001 From: boris Date: Fri, 19 Jun 2026 10:20:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E9=A2=84=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E5=B8=82=E5=80=BC=E5=86=B3=E7=AD=96=E5=8F=A3=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/fidc-core/src/data.rs | 56 ++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/crates/fidc-core/src/data.rs b/crates/fidc-core/src/data.rs index cc37c73..f2ef76d 100644 --- a/crates/fidc-core/src/data.rs +++ b/crates/fidc-core/src/data.rs @@ -478,7 +478,17 @@ pub fn decision_adjusted_cap_bn( raw_cap_bn * market.prev_close / market.close } +fn factor_market_cap_is_decision_adjusted(factor: &DailyFactorSnapshot) -> bool { + factor + .extra_factors + .get("__market_cap_decision_adjusted") + .is_some_and(|value| value.is_finite() && *value > 0.0) +} + pub fn decision_market_cap_bn(factor: &DailyFactorSnapshot, market: &DailyMarketSnapshot) -> f64 { + if factor_market_cap_is_decision_adjusted(factor) { + return factor.market_cap_bn; + } decision_adjusted_cap_bn(factor.date, factor.market_cap_bn, market) } @@ -486,6 +496,9 @@ pub fn decision_free_float_cap_bn( factor: &DailyFactorSnapshot, market: &DailyMarketSnapshot, ) -> f64 { + if factor_market_cap_is_decision_adjusted(factor) { + return factor.free_float_cap_bn; + } decision_adjusted_cap_bn(factor.date, factor.free_float_cap_bn, market) } @@ -3973,6 +3986,49 @@ mod tests { assert!((rows[1].market_cap_bn - 10.0).abs() < 1e-9); } + #[test] + fn decision_market_cap_keeps_pre_adjusted_factor() { + let date = NaiveDate::parse_from_str("2025-01-06", "%Y-%m-%d").unwrap(); + let market = DailyMarketSnapshot { + date, + symbol: "000001.SZ".to_string(), + timestamp: Some("2025-01-06 10:18:00".to_string()), + day_open: 10.0, + open: 10.0, + high: 20.0, + low: 10.0, + close: 20.0, + last_price: 10.0, + bid1: 10.0, + ask1: 10.0, + prev_close: 10.0, + volume: 100_000, + tick_volume: 1_000, + bid1_volume: 1_000, + ask1_volume: 1_000, + trading_phase: Some("continuous".to_string()), + paused: false, + upper_limit: 11.0, + lower_limit: 9.0, + price_tick: 0.01, + }; + let mut extra_factors = BTreeMap::new(); + extra_factors.insert("__market_cap_decision_adjusted".to_string(), 1.0); + let factor = DailyFactorSnapshot { + date, + symbol: "000001.SZ".to_string(), + market_cap_bn: 12.0, + free_float_cap_bn: 4.0, + pe_ttm: 10.0, + turnover_ratio: Some(1.0), + effective_turnover_ratio: Some(1.0), + extra_factors, + }; + + assert!((decision_market_cap_bn(&factor, &market) - 12.0).abs() < 1e-9); + assert!((decision_free_float_cap_bn(&factor, &market) - 4.0).abs() < 1e-9); + } + #[test] fn benchmark_decision_close_windows_exclude_current_close() { let series = BenchmarkPriceSeries::new(&[