From 1a402f2048c405f323926f3c12638443bffad596 Mon Sep 17 00:00:00 2001 From: boris Date: Mon, 11 May 2026 20:38:12 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=9E=E7=8E=B0=E5=B8=82=E5=80=BC=E5=8C=BA?= =?UTF-8?q?=E9=97=B4padding=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加padding_ratio、min_padding、max_padding配置参数 - 在市值区间计算中应用padding扩大选股范围 - 更新OmniMicroCapConfig、CnSmallCapRotationConfig和DynamicMarketCapBandSelector - AiQuant V1.0.4默认padding: ratio=0.5, min=12.5, max=30.0 - 目标:增加候选股票数量,匹配AiQuant行为 --- .../fidc-core/src/platform_strategy_spec.rs | 9 +++++ crates/fidc-core/src/strategy.rs | 34 ++++++++++++++++++- crates/fidc-core/src/universe.rs | 24 +++++++++++-- 3 files changed, 64 insertions(+), 3 deletions(-) diff --git a/crates/fidc-core/src/platform_strategy_spec.rs b/crates/fidc-core/src/platform_strategy_spec.rs index cd49a22..751ff24 100644 --- a/crates/fidc-core/src/platform_strategy_spec.rs +++ b/crates/fidc-core/src/platform_strategy_spec.rs @@ -114,6 +114,15 @@ pub struct DynamicRangeConfig { pub cap_span: Option, #[serde(default)] pub xs: Option, + /// Padding ratio to expand the market cap range (e.g., 0.5 means 50% of span) + #[serde(default)] + pub padding_ratio: Option, + /// Minimum padding in billion yuan + #[serde(default)] + pub min_padding: Option, + /// Maximum padding in billion yuan + #[serde(default)] + pub max_padding: Option, } #[derive(Debug, Clone, Default, Deserialize, Serialize)] diff --git a/crates/fidc-core/src/strategy.rs b/crates/fidc-core/src/strategy.rs index 728359e..1af2fb6 100644 --- a/crates/fidc-core/src/strategy.rs +++ b/crates/fidc-core/src/strategy.rs @@ -1090,6 +1090,9 @@ pub struct CnSmallCapRotationConfig { pub base_index_level: f64, pub base_cap_floor: f64, pub cap_span: f64, + pub padding_ratio: f64, + pub min_padding: f64, + pub max_padding: f64, pub short_ma_days: usize, pub long_ma_days: usize, pub stock_short_ma_days: usize, @@ -1114,6 +1117,9 @@ impl CnSmallCapRotationConfig { base_index_level: 2000.0, base_cap_floor: 7.0, cap_span: 10.0, + padding_ratio: 0.5, + min_padding: 8.0, + max_padding: 20.0, short_ma_days: 3, long_ma_days: 5, stock_short_ma_days: 3, @@ -1138,6 +1144,9 @@ impl CnSmallCapRotationConfig { base_index_level: 2000.0, base_cap_floor: 7.0, cap_span: 10.0, + padding_ratio: 0.5, + min_padding: 8.0, + max_padding: 20.0, short_ma_days: 5, long_ma_days: 10, stock_short_ma_days: 5, @@ -1185,6 +1194,9 @@ impl CnSmallCapRotationStrategy { config.cap_span, config.xs, config.stocknum, + config.padding_ratio, + config.min_padding, + config.max_padding, ), config, last_gross_exposure: None, @@ -1508,6 +1520,9 @@ pub struct OmniMicroCapConfig { pub base_index_level: f64, pub base_cap_floor: f64, pub cap_span: f64, + pub padding_ratio: f64, + pub min_padding: f64, + pub max_padding: f64, pub benchmark_signal_symbol: String, pub benchmark_short_ma_days: usize, pub benchmark_long_ma_days: usize, @@ -1531,6 +1546,9 @@ impl OmniMicroCapConfig { base_index_level: 2000.0, base_cap_floor: 7.0, cap_span: 10.0, + padding_ratio: 0.5, + min_padding: 8.0, + max_padding: 20.0, benchmark_signal_symbol: "000001.SH".to_string(), benchmark_short_ma_days: 5, benchmark_long_ma_days: 10, @@ -1556,6 +1574,9 @@ impl OmniMicroCapConfig { base_index_level: 2000.0, base_cap_floor: 7.0, cap_span: 25.0, + padding_ratio: 0.5, + min_padding: 12.5, + max_padding: 30.0, benchmark_signal_symbol: "000852.SH".to_string(), benchmark_short_ma_days: 5, benchmark_long_ma_days: 20, @@ -2167,7 +2188,18 @@ impl OmniMicroCapStrategy { let y = (index_level - self.config.base_index_level) * self.config.xs + self.config.base_cap_floor; let start = y.round(); - (start, start + self.config.cap_span) + let end = start + self.config.cap_span; + + // Apply padding to expand the range + let span = end - start; + let padding = (span * self.config.padding_ratio) + .max(self.config.min_padding) + .min(self.config.max_padding); + + let lower_bound = (start - padding).max(0.0); + let upper_bound = end + padding; + + (lower_bound, upper_bound) } fn stock_passes_ma_filter( diff --git a/crates/fidc-core/src/universe.rs b/crates/fidc-core/src/universe.rs index ed19de0..0dbe3bd 100644 --- a/crates/fidc-core/src/universe.rs +++ b/crates/fidc-core/src/universe.rs @@ -78,6 +78,9 @@ pub struct DynamicMarketCapBandSelector { pub cap_span: f64, pub xs: f64, pub top_n: usize, + pub padding_ratio: f64, + pub min_padding: f64, + pub max_padding: f64, } impl DynamicMarketCapBandSelector { @@ -87,6 +90,9 @@ impl DynamicMarketCapBandSelector { cap_span: f64, xs: f64, top_n: usize, + padding_ratio: f64, + min_padding: f64, + max_padding: f64, ) -> Self { Self { base_index_level, @@ -94,11 +100,14 @@ impl DynamicMarketCapBandSelector { cap_span, xs, top_n, + padding_ratio, + min_padding, + max_padding, } } pub fn demo(top_n: usize) -> Self { - Self::new(2000.0, 7.0, 10.0, 4.0 / 500.0, top_n) + Self::new(2000.0, 7.0, 10.0, 4.0 / 500.0, top_n, 0.5, 8.0, 20.0) } pub fn regime(&self, benchmark_level: f64) -> BandRegime { @@ -114,7 +123,18 @@ impl DynamicMarketCapBandSelector { pub fn band_for_level(&self, benchmark_level: f64) -> (f64, f64) { let start = ((benchmark_level - self.base_index_level) * self.xs) + self.base_cap_floor; let low = start.round(); - (low, low + self.cap_span) + let high = low + self.cap_span; + + // Apply padding to expand the range + let span = high - low; + let padding = (span * self.padding_ratio) + .max(self.min_padding) + .min(self.max_padding); + + let lower_bound = (low - padding).max(0.0); + let upper_bound = high + padding; + + (lower_bound, upper_bound) } }