补充缺失风控状态拒绝
This commit is contained in:
@@ -300,6 +300,9 @@ impl ChinaAShareRiskControl {
|
||||
{
|
||||
return Some(reason);
|
||||
}
|
||||
if Self::missing_risk_state_rejected(candidate, config, scope) {
|
||||
return Some("missing_risk_state");
|
||||
}
|
||||
let reject_paused = match scope {
|
||||
RiskCheckScope::Selection => config.static_rules.reject_paused_selection,
|
||||
RiskCheckScope::Buy => config.static_rules.reject_paused_buy,
|
||||
@@ -343,6 +346,45 @@ impl ChinaAShareRiskControl {
|
||||
None
|
||||
}
|
||||
|
||||
fn missing_risk_state_rejected(
|
||||
candidate: &CandidateEligibility,
|
||||
config: &FidcRiskControlConfig,
|
||||
scope: RiskCheckScope,
|
||||
) -> bool {
|
||||
let Some(code) = candidate
|
||||
.risk_level_code
|
||||
.as_deref()
|
||||
.map(str::trim)
|
||||
.filter(|value| value.starts_with("missing_risk_state"))
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
if code.is_empty() {
|
||||
return false;
|
||||
}
|
||||
match scope {
|
||||
RiskCheckScope::Selection => {
|
||||
config.static_rules.reject_st_selection
|
||||
|| config.static_rules.reject_paused_selection
|
||||
|| config.static_rules.reject_inactive_selection
|
||||
|| config.static_rules.reject_new_listing_selection
|
||||
|| config.static_rules.reject_kcb_selection
|
||||
|| config.static_rules.reject_one_yuan_selection
|
||||
|| config.static_rules.respect_allow_buy_sell
|
||||
}
|
||||
RiskCheckScope::Buy => {
|
||||
config.static_rules.reject_st_buy
|
||||
|| config.static_rules.reject_paused_buy
|
||||
|| config.static_rules.reject_inactive_buy
|
||||
|| config.static_rules.reject_new_listing_buy
|
||||
|| config.static_rules.reject_kcb_buy
|
||||
|| config.static_rules.reject_one_yuan_buy
|
||||
|| config.static_rules.respect_allow_buy_sell
|
||||
}
|
||||
RiskCheckScope::Sell => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn buy_rejection_reason(
|
||||
date: NaiveDate,
|
||||
candidate: &CandidateEligibility,
|
||||
@@ -598,6 +640,64 @@ mod tests {
|
||||
assert_eq!(configured_reason, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_risk_state_rejects_selection_and_buy_when_static_filters_enabled() {
|
||||
let date = d(2025, 1, 2);
|
||||
let mut candidate = candidate(date);
|
||||
candidate.risk_level_code = Some("missing_risk_state:is_st,paused,allow_buy".to_string());
|
||||
let market = market(date, 6.27, 5.63);
|
||||
|
||||
let selection_reason =
|
||||
ChinaAShareRiskControl::selection_rejection_reason(date, &candidate, &market, None);
|
||||
let buy_reason =
|
||||
ChinaAShareRiskControl::buy_rejection_reason(date, &candidate, &market, None, 6.27);
|
||||
let sell_reason = ChinaAShareRiskControl::sell_rejection_reason(
|
||||
date,
|
||||
&candidate,
|
||||
&market,
|
||||
None,
|
||||
Some(&position(d(2024, 12, 31))),
|
||||
6.27,
|
||||
);
|
||||
|
||||
assert_eq!(selection_reason, Some("missing_risk_state"));
|
||||
assert_eq!(buy_reason, Some("missing_risk_state"));
|
||||
assert_eq!(sell_reason, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn missing_risk_state_can_be_relaxed_by_disabling_static_filters() {
|
||||
let date = d(2025, 1, 2);
|
||||
let mut candidate = candidate(date);
|
||||
candidate.allow_sell = true;
|
||||
candidate.risk_level_code = Some("missing_risk_state:is_st,paused,allow_buy".to_string());
|
||||
let market = market(date, 6.27, 5.63);
|
||||
let mut config = FidcRiskControlConfig::default();
|
||||
config.static_rules.reject_st_selection = false;
|
||||
config.static_rules.reject_st_buy = false;
|
||||
config.static_rules.reject_paused_selection = false;
|
||||
config.static_rules.reject_paused_buy = false;
|
||||
config.static_rules.reject_inactive_selection = false;
|
||||
config.static_rules.reject_inactive_buy = false;
|
||||
config.static_rules.reject_new_listing_selection = false;
|
||||
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_one_yuan_selection = false;
|
||||
config.static_rules.reject_one_yuan_buy = false;
|
||||
config.static_rules.respect_allow_buy_sell = false;
|
||||
|
||||
let selection_reason = ChinaAShareRiskControl::selection_rejection_reason_with_config(
|
||||
date, &candidate, &market, None, &config,
|
||||
);
|
||||
let buy_reason = ChinaAShareRiskControl::buy_rejection_reason_with_config(
|
||||
date, &candidate, &market, None, 6.27, &config,
|
||||
);
|
||||
|
||||
assert_eq!(selection_reason, None);
|
||||
assert_eq!(buy_reason, None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn configurable_upper_limit_buy_filter_can_be_disabled() {
|
||||
let date = d(2025, 1, 2);
|
||||
|
||||
Reference in New Issue
Block a user