补齐FIDC北交所风控开关
This commit is contained in:
@@ -25,6 +25,8 @@ pub struct StaticRiskRuleConfig {
|
||||
pub reject_new_listing_buy: bool,
|
||||
pub reject_kcb_selection: bool,
|
||||
pub reject_kcb_buy: bool,
|
||||
pub reject_bjse_selection: bool,
|
||||
pub reject_bjse_buy: bool,
|
||||
pub reject_one_yuan_selection: bool,
|
||||
pub reject_one_yuan_buy: bool,
|
||||
pub respect_allow_buy_sell: bool,
|
||||
@@ -53,6 +55,8 @@ impl Default for StaticRiskRuleConfig {
|
||||
reject_new_listing_buy: true,
|
||||
reject_kcb_selection: true,
|
||||
reject_kcb_buy: true,
|
||||
reject_bjse_selection: true,
|
||||
reject_bjse_buy: true,
|
||||
reject_one_yuan_selection: true,
|
||||
reject_one_yuan_buy: true,
|
||||
respect_allow_buy_sell: true,
|
||||
@@ -358,6 +362,14 @@ impl ChinaAShareRiskControl {
|
||||
if reject_kcb && (candidate.is_kcb || symbol_is_kcb(&candidate.symbol)) {
|
||||
return Some("kcb");
|
||||
}
|
||||
let reject_bjse = match scope {
|
||||
RiskCheckScope::Selection => config.static_rules.reject_bjse_selection,
|
||||
RiskCheckScope::Buy => config.static_rules.reject_bjse_buy,
|
||||
RiskCheckScope::Sell => false,
|
||||
};
|
||||
if reject_bjse && symbol_is_bjse(&candidate.symbol) {
|
||||
return Some("bjse");
|
||||
}
|
||||
let reject_one_yuan = match scope {
|
||||
RiskCheckScope::Selection => config.static_rules.reject_one_yuan_selection,
|
||||
RiskCheckScope::Buy => config.static_rules.reject_one_yuan_buy,
|
||||
@@ -514,6 +526,11 @@ fn symbol_is_kcb(symbol: &str) -> bool {
|
||||
(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")
|
||||
}
|
||||
|
||||
fn missing_risk_state_fields(code: &str) -> Vec<String> {
|
||||
let Some((_, fields)) = code.split_once(':') else {
|
||||
return Vec::new();
|
||||
@@ -534,6 +551,7 @@ fn missing_selection_risk_state_rejected(code: &str, config: &FidcRiskControlCon
|
||||
|| config.static_rules.reject_inactive_selection
|
||||
|| config.static_rules.reject_new_listing_selection
|
||||
|| config.static_rules.reject_kcb_selection
|
||||
|| config.static_rules.reject_bjse_selection
|
||||
|| config.static_rules.reject_one_yuan_selection
|
||||
|| config.static_rules.reject_upper_limit_selection
|
||||
|| config.static_rules.reject_lower_limit_selection
|
||||
@@ -550,6 +568,7 @@ fn missing_buy_risk_state_rejected(code: &str, config: &FidcRiskControlConfig) -
|
||||
|| config.static_rules.reject_inactive_buy
|
||||
|| config.static_rules.reject_new_listing_buy
|
||||
|| config.static_rules.reject_kcb_buy
|
||||
|| config.static_rules.reject_bjse_buy
|
||||
|| config.static_rules.reject_one_yuan_buy
|
||||
|| config.static_rules.reject_upper_limit_buy
|
||||
|| config.static_rules.respect_allow_buy_sell;
|
||||
@@ -606,8 +625,18 @@ fn missing_single_field_rejected(
|
||||
RiskCheckScope::Sell => false,
|
||||
},
|
||||
"is_kcb" | "kcb" | "board" | "market_board" => match scope {
|
||||
RiskCheckScope::Selection => config.static_rules.reject_kcb_selection,
|
||||
RiskCheckScope::Buy => config.static_rules.reject_kcb_buy,
|
||||
RiskCheckScope::Selection => {
|
||||
config.static_rules.reject_kcb_selection
|
||||
|| config.static_rules.reject_bjse_selection
|
||||
}
|
||||
RiskCheckScope::Buy => {
|
||||
config.static_rules.reject_kcb_buy || config.static_rules.reject_bjse_buy
|
||||
}
|
||||
RiskCheckScope::Sell => false,
|
||||
},
|
||||
"is_bjse" | "bjse" | "bse" | "beijing_exchange" | "north_exchange" => match scope {
|
||||
RiskCheckScope::Selection => config.static_rules.reject_bjse_selection,
|
||||
RiskCheckScope::Buy => config.static_rules.reject_bjse_buy,
|
||||
RiskCheckScope::Sell => false,
|
||||
},
|
||||
"is_one_yuan" | "one_yuan" => match scope {
|
||||
@@ -644,6 +673,7 @@ fn missing_single_field_rejected(
|
||||
|| config.static_rules.reject_inactive_selection
|
||||
|| config.static_rules.reject_new_listing_selection
|
||||
|| config.static_rules.reject_kcb_selection
|
||||
|| config.static_rules.reject_bjse_selection
|
||||
|| config.static_rules.reject_one_yuan_selection
|
||||
|| config.static_rules.reject_upper_limit_selection
|
||||
|| config.static_rules.reject_lower_limit_selection
|
||||
@@ -655,6 +685,7 @@ fn missing_single_field_rejected(
|
||||
|| config.static_rules.reject_inactive_buy
|
||||
|| config.static_rules.reject_new_listing_buy
|
||||
|| config.static_rules.reject_kcb_buy
|
||||
|| config.static_rules.reject_bjse_buy
|
||||
|| config.static_rules.reject_one_yuan_buy
|
||||
|| config.static_rules.reject_upper_limit_buy
|
||||
|| config.static_rules.respect_allow_buy_sell
|
||||
@@ -813,6 +844,33 @@ mod tests {
|
||||
assert_eq!(configured_reason, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn configurable_bjse_filter_can_be_disabled() {
|
||||
let date = d(2025, 1, 2);
|
||||
let mut candidate = candidate(date);
|
||||
candidate.symbol = "430047.BJ".to_string();
|
||||
candidate.allow_sell = true;
|
||||
let market = market(date, 6.27, 5.63);
|
||||
let default_selection =
|
||||
ChinaAShareRiskControl::selection_rejection_reason(date, &candidate, &market, None);
|
||||
let default_buy =
|
||||
ChinaAShareRiskControl::buy_rejection_reason(date, &candidate, &market, None, 6.27);
|
||||
let mut config = FidcRiskControlConfig::default();
|
||||
config.static_rules.reject_bjse_selection = false;
|
||||
config.static_rules.reject_bjse_buy = false;
|
||||
let configured_selection = ChinaAShareRiskControl::selection_rejection_reason_with_config(
|
||||
date, &candidate, &market, None, &config,
|
||||
);
|
||||
let configured_buy = ChinaAShareRiskControl::buy_rejection_reason_with_config(
|
||||
date, &candidate, &market, None, 6.27, &config,
|
||||
);
|
||||
|
||||
assert_eq!(default_selection, Some("bjse"));
|
||||
assert_eq!(default_buy, Some("bjse"));
|
||||
assert_eq!(configured_selection, None);
|
||||
assert_eq!(configured_buy, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn concrete_kcb_reason_wins_over_generic_missing_risk_state() {
|
||||
let date = d(2025, 1, 2);
|
||||
@@ -994,6 +1052,8 @@ mod tests {
|
||||
config.static_rules.reject_new_listing_buy = false;
|
||||
config.static_rules.reject_kcb_selection = false;
|
||||
config.static_rules.reject_kcb_buy = false;
|
||||
config.static_rules.reject_bjse_selection = false;
|
||||
config.static_rules.reject_bjse_buy = false;
|
||||
config.static_rules.reject_one_yuan_selection = false;
|
||||
config.static_rules.reject_one_yuan_buy = false;
|
||||
config.static_rules.respect_allow_buy_sell = false;
|
||||
|
||||
Reference in New Issue
Block a user