fix: preserve authoritative STAR market classification in risk checks

This commit is contained in:
boris
2026-09-08 22:42:33 +08:00
parent 326438aac9
commit 078839b0f3
3 changed files with 51 additions and 25 deletions
+20 -6
View File
@@ -397,7 +397,7 @@ impl ChinaAShareRiskControl {
RiskCheckScope::Buy => config.static_rules.reject_kcb_buy,
RiskCheckScope::Sell => false,
};
if reject_kcb && (candidate.is_kcb || symbol_is_kcb(&candidate.symbol)) {
if reject_kcb && candidate.is_kcb {
return Some("kcb");
}
let reject_bjse = match scope {
@@ -600,11 +600,6 @@ impl ChinaAShareRiskControl {
}
}
fn symbol_is_kcb(symbol: &str) -> bool {
let normalized = symbol.trim().to_ascii_uppercase();
(normalized.starts_with("688") || normalized.starts_with("689")) && normalized.ends_with(".SH")
}
fn symbol_is_bjse(symbol: &str) -> bool {
let normalized = symbol.trim().to_ascii_uppercase();
normalized.ends_with(".BJ") || normalized.ends_with(".BSE") || normalized.ends_with(".BE")
@@ -1009,6 +1004,24 @@ mod tests {
assert_eq!(configured_reason, None);
}
#[test]
fn kcb_filter_uses_classification_instead_of_security_code() {
let date = d(2025, 1, 2);
let market = market(date, 6.27, 5.63);
let mut candidate = candidate(date);
let config = FidcRiskControlConfig::default();
for symbol in ["688001.SH", "689001.SH", "000001.SZ"] {
candidate.symbol = symbol.to_string();
for is_kcb in [false, true] {
candidate.is_kcb = is_kcb;
let reason = ChinaAShareRiskControl::buy_rejection_reason_with_config(
date, &candidate, &market, None, 6.27, &config,
);
assert_eq!(reason, is_kcb.then_some("kcb"), "{symbol}");
}
}
}
#[test]
fn st_and_star_st_filters_are_independent() {
let date = d(2025, 1, 2);
@@ -1139,6 +1152,7 @@ mod tests {
let date = d(2025, 1, 2);
let mut candidate = candidate(date);
candidate.symbol = "688506.SH".to_string();
candidate.is_kcb = true;
candidate.risk_level_code = Some("missing_risk_state".to_string());
let market = market(date, 6.27, 5.63);
let mut config = FidcRiskControlConfig::default();