修正内置选择器next-open风控语义
This commit is contained in:
@@ -1506,6 +1506,7 @@ impl Strategy for CnSmallCapRotationStrategy {
|
|||||||
data: ctx.data,
|
data: ctx.data,
|
||||||
dynamic_universe: ctx.dynamic_universe,
|
dynamic_universe: ctx.dynamic_universe,
|
||||||
risk_config: Some(&self.config.risk_config),
|
risk_config: Some(&self.config.risk_config),
|
||||||
|
defer_selection_risk: ctx.is_lagged_execution(),
|
||||||
});
|
});
|
||||||
let before_ma_count = selected_before_ma.len();
|
let before_ma_count = selected_before_ma.len();
|
||||||
let mut ma_rejects = Vec::new();
|
let mut ma_rejects = Vec::new();
|
||||||
|
|||||||
@@ -50,15 +50,16 @@ pub struct SelectionContext<'a> {
|
|||||||
pub data: &'a DataSet,
|
pub data: &'a DataSet,
|
||||||
pub dynamic_universe: Option<&'a BTreeSet<String>>,
|
pub dynamic_universe: Option<&'a BTreeSet<String>>,
|
||||||
pub risk_config: Option<&'a FidcRiskControlConfig>,
|
pub risk_config: Option<&'a FidcRiskControlConfig>,
|
||||||
|
pub defer_selection_risk: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SelectionContext<'_> {
|
impl SelectionContext<'_> {
|
||||||
fn eligible_universe(&self) -> Vec<EligibleUniverseSnapshot> {
|
fn eligible_universe(&self) -> Vec<EligibleUniverseSnapshot> {
|
||||||
let eligible = match self.risk_config {
|
let eligible = match (self.risk_config, self.defer_selection_risk) {
|
||||||
Some(risk_config) => self
|
(Some(risk_config), false) => self
|
||||||
.data
|
.data
|
||||||
.eligible_universe_on_with_risk_config(self.decision_date, risk_config),
|
.eligible_universe_on_with_risk_config(self.decision_date, risk_config),
|
||||||
None => self.data.eligible_universe_on(self.decision_date).to_vec(),
|
_ => self.data.eligible_universe_on(self.decision_date).to_vec(),
|
||||||
};
|
};
|
||||||
match self.dynamic_universe {
|
match self.dynamic_universe {
|
||||||
Some(symbols) if !symbols.is_empty() => eligible
|
Some(symbols) if !symbols.is_empty() => eligible
|
||||||
@@ -406,6 +407,7 @@ mod tests {
|
|||||||
data: &data,
|
data: &data,
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
risk_config: Some(&risk_config),
|
risk_config: Some(&risk_config),
|
||||||
|
defer_selection_risk: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let rules = diagnostics
|
let rules = diagnostics
|
||||||
@@ -463,6 +465,7 @@ mod tests {
|
|||||||
data: &data,
|
data: &data,
|
||||||
dynamic_universe: None,
|
dynamic_universe: None,
|
||||||
risk_config: Some(&risk_config),
|
risk_config: Some(&risk_config),
|
||||||
|
defer_selection_risk: false,
|
||||||
});
|
});
|
||||||
|
|
||||||
let selected_symbols = selected
|
let selected_symbols = selected
|
||||||
@@ -481,4 +484,61 @@ mod tests {
|
|||||||
assert!(rules.contains("st"), "{:?}", diagnostics.risk_decisions);
|
assert!(rules.contains("st"), "{:?}", diagnostics.risk_decisions);
|
||||||
assert!(rules.contains("kcb"), "{:?}", diagnostics.risk_decisions);
|
assert!(rules.contains("kcb"), "{:?}", diagnostics.risk_decisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn selector_can_defer_configured_selection_risk_without_losing_diagnostics() {
|
||||||
|
let data = DataSet::from_components(
|
||||||
|
vec![
|
||||||
|
instrument("000001.SZ"),
|
||||||
|
instrument("688001.SH"),
|
||||||
|
instrument("000002.SZ"),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
market("000001.SZ", 10.0),
|
||||||
|
market("688001.SH", 10.0),
|
||||||
|
market("000002.SZ", 10.0),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
factor("000001.SZ", 8.0),
|
||||||
|
factor("688001.SH", 9.0),
|
||||||
|
factor("000002.SZ", 10.0),
|
||||||
|
],
|
||||||
|
vec![
|
||||||
|
candidate("000001.SZ", true, false),
|
||||||
|
candidate("688001.SH", false, true),
|
||||||
|
candidate("000002.SZ", false, false),
|
||||||
|
],
|
||||||
|
vec![benchmark()],
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let selector = DynamicMarketCapBandSelector::new(2000.0, 7.0, 10.0, 0.0, 10, 0.0, 0.0, 0.0);
|
||||||
|
let mut risk_config = FidcRiskControlConfig::default();
|
||||||
|
risk_config.static_rules.reject_st_selection = true;
|
||||||
|
risk_config.static_rules.reject_kcb_selection = true;
|
||||||
|
|
||||||
|
let (selected, diagnostics) = selector.select_with_diagnostics(&SelectionContext {
|
||||||
|
decision_date: d(),
|
||||||
|
benchmark: &benchmark(),
|
||||||
|
reference_level: 2000.0,
|
||||||
|
data: &data,
|
||||||
|
dynamic_universe: None,
|
||||||
|
risk_config: Some(&risk_config),
|
||||||
|
defer_selection_risk: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
let selected_symbols = selected
|
||||||
|
.iter()
|
||||||
|
.map(|candidate| candidate.symbol.as_str())
|
||||||
|
.collect::<BTreeSet<_>>();
|
||||||
|
assert!(selected_symbols.contains("000001.SZ"));
|
||||||
|
assert!(selected_symbols.contains("688001.SH"));
|
||||||
|
assert!(selected_symbols.contains("000002.SZ"));
|
||||||
|
let rules = diagnostics
|
||||||
|
.risk_decisions
|
||||||
|
.iter()
|
||||||
|
.map(|decision| decision.rule_code.as_str())
|
||||||
|
.collect::<BTreeSet<_>>();
|
||||||
|
assert!(rules.contains("st"), "{:?}", diagnostics.risk_decisions);
|
||||||
|
assert!(rules.contains("kcb"), "{:?}", diagnostics.risk_decisions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user