Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3a3091a2cf | |||
| d2aa16a2f0 | |||
| 0576cf9b6d | |||
| 636e0dfd05 |
@@ -10353,6 +10353,7 @@ impl PlatformExprStrategy {
|
|||||||
) -> (Vec<u32>, Vec<FidcRiskDecisionAudit>) {
|
) -> (Vec<u32>, Vec<FidcRiskDecisionAudit>) {
|
||||||
let mut symbol_ids = Vec::new();
|
let mut symbol_ids = Vec::new();
|
||||||
let mut decisions = Vec::new();
|
let mut decisions = Vec::new();
|
||||||
|
let selection_checks_enabled = self.config.risk_config.static_rules.selection_checks_enabled();
|
||||||
let mut eligible_symbols = vec![false; ctx.data.symbol_count()];
|
let mut eligible_symbols = vec![false; ctx.data.symbol_count()];
|
||||||
let execution_day = ctx.data.daily_snapshot_view(date);
|
let execution_day = ctx.data.daily_snapshot_view(date);
|
||||||
let factor_day = ctx.data.daily_snapshot_view(factor_date);
|
let factor_day = ctx.data.daily_snapshot_view(factor_date);
|
||||||
@@ -10398,7 +10399,9 @@ impl PlatformExprStrategy {
|
|||||||
let Some(market) = execution_day.market(symbol_id) else {
|
let Some(market) = execution_day.market(symbol_id) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
let (reject_from_universe, selection_decision) = if collect_risk_decisions {
|
let (reject_from_universe, selection_decision) = if !selection_checks_enabled {
|
||||||
|
(false, None)
|
||||||
|
} else if collect_risk_decisions {
|
||||||
let decision = ChinaAShareRiskControl::selection_rejection_decision_with_config(
|
let decision = ChinaAShareRiskControl::selection_rejection_decision_with_config(
|
||||||
date,
|
date,
|
||||||
candidate,
|
candidate,
|
||||||
|
|||||||
@@ -76,6 +76,26 @@ impl Default for StaticRiskRuleConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl StaticRiskRuleConfig {
|
||||||
|
pub(crate) fn selection_checks_enabled(&self) -> bool {
|
||||||
|
(self.blacklist_enabled && !self.blacklisted_symbols.is_empty())
|
||||||
|
|| self.selection_state_checks_enabled()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn selection_state_checks_enabled(&self) -> bool {
|
||||||
|
self.reject_st_selection
|
||||||
|
|| self.reject_star_st_selection
|
||||||
|
|| self.reject_paused_selection
|
||||||
|
|| self.reject_inactive_selection
|
||||||
|
|| self.reject_new_listing_selection
|
||||||
|
|| self.reject_kcb_selection
|
||||||
|
|| self.reject_bjse_selection
|
||||||
|
|| self.reject_one_yuan_selection
|
||||||
|
|| self.reject_upper_limit_selection
|
||||||
|
|| self.reject_lower_limit_selection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct TradingConstraintConfig {
|
pub struct TradingConstraintConfig {
|
||||||
/// Shared execution limits. These fields intentionally use the same
|
/// Shared execution limits. These fields intentionally use the same
|
||||||
@@ -654,16 +674,7 @@ fn missing_risk_state_fields(code: &str) -> Vec<String> {
|
|||||||
fn missing_selection_risk_state_rejected(code: &str, config: &FidcRiskControlConfig) -> bool {
|
fn missing_selection_risk_state_rejected(code: &str, config: &FidcRiskControlConfig) -> bool {
|
||||||
let fields = missing_risk_state_fields(code);
|
let fields = missing_risk_state_fields(code);
|
||||||
if fields.is_empty() {
|
if fields.is_empty() {
|
||||||
return config.static_rules.reject_st_selection
|
return config.static_rules.selection_state_checks_enabled();
|
||||||
|| config.static_rules.reject_star_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_bjse_selection
|
|
||||||
|| config.static_rules.reject_one_yuan_selection
|
|
||||||
|| config.static_rules.reject_upper_limit_selection
|
|
||||||
|| config.static_rules.reject_lower_limit_selection;
|
|
||||||
}
|
}
|
||||||
missing_field_rejected(&fields, config, RiskCheckScope::Selection)
|
missing_field_rejected(&fields, config, RiskCheckScope::Selection)
|
||||||
}
|
}
|
||||||
@@ -778,18 +789,7 @@ fn missing_single_field_rejected(
|
|||||||
RiskCheckScope::Sell => config.static_rules.reject_lower_limit_sell,
|
RiskCheckScope::Sell => config.static_rules.reject_lower_limit_sell,
|
||||||
},
|
},
|
||||||
_ => match scope {
|
_ => match scope {
|
||||||
RiskCheckScope::Selection => {
|
RiskCheckScope::Selection => config.static_rules.selection_state_checks_enabled(),
|
||||||
config.static_rules.reject_st_selection
|
|
||||||
|| config.static_rules.reject_star_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_bjse_selection
|
|
||||||
|| config.static_rules.reject_one_yuan_selection
|
|
||||||
|| config.static_rules.reject_upper_limit_selection
|
|
||||||
|| config.static_rules.reject_lower_limit_selection
|
|
||||||
}
|
|
||||||
RiskCheckScope::Buy => {
|
RiskCheckScope::Buy => {
|
||||||
config.static_rules.reject_st_buy
|
config.static_rules.reject_st_buy
|
||||||
|| config.static_rules.reject_star_st_buy
|
|| config.static_rules.reject_star_st_buy
|
||||||
@@ -914,6 +914,69 @@ mod tests {
|
|||||||
position
|
position
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn selection_check_activation_covers_every_configured_flag_and_blacklist_state() {
|
||||||
|
let fields = [
|
||||||
|
"reject_st_selection", "reject_star_st_selection", "reject_paused_selection",
|
||||||
|
"reject_inactive_selection", "reject_new_listing_selection", "reject_kcb_selection",
|
||||||
|
"reject_bjse_selection", "reject_one_yuan_selection", "reject_upper_limit_selection",
|
||||||
|
"reject_lower_limit_selection",
|
||||||
|
];
|
||||||
|
let base = serde_json::to_value(StaticRiskRuleConfig::default()).unwrap();
|
||||||
|
let declared = base.as_object().unwrap().keys()
|
||||||
|
.filter(|key| key.ends_with("_selection"))
|
||||||
|
.map(String::as_str).collect::<BTreeSet<_>>();
|
||||||
|
assert_eq!(declared, fields.into_iter().collect());
|
||||||
|
for mask in 0..(1_u32 << fields.len()) {
|
||||||
|
for (blacklist_enabled, populated) in [(false, false), (false, true), (true, false), (true, true)] {
|
||||||
|
let mut value = base.clone();
|
||||||
|
for (bit, field) in fields.iter().enumerate() {
|
||||||
|
value[*field] = serde_json::json!(mask & (1 << bit) != 0);
|
||||||
|
}
|
||||||
|
value["blacklist_enabled"] = serde_json::json!(blacklist_enabled);
|
||||||
|
value["blacklisted_symbols"] = if populated {
|
||||||
|
serde_json::json!(["002633.SZ"])
|
||||||
|
} else { serde_json::json!([]) };
|
||||||
|
let config: StaticRiskRuleConfig = serde_json::from_value(value).unwrap();
|
||||||
|
assert_eq!(config.selection_checks_enabled(), mask != 0 || (blacklist_enabled && populated));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn inactive_selection_checks_preserve_missing_facts_and_execution_rejections() {
|
||||||
|
let date = d(2025, 2, 6);
|
||||||
|
let mut candidate = candidate(date);
|
||||||
|
candidate.is_st = true;
|
||||||
|
candidate.is_star_st = true;
|
||||||
|
candidate.is_paused = true;
|
||||||
|
candidate.is_new_listing = true;
|
||||||
|
candidate.is_kcb = true;
|
||||||
|
candidate.is_one_yuan = true;
|
||||||
|
candidate.allow_buy = false;
|
||||||
|
let snapshot = market(date, 0.9, 0.9);
|
||||||
|
let config = FidcRiskControlConfig::default();
|
||||||
|
assert!(!config.static_rules.selection_checks_enabled());
|
||||||
|
let instrument = instrument("delisted", Some(date));
|
||||||
|
for code in [None, Some("not_listed"), Some("inactive_or_delisted"),
|
||||||
|
Some("missing_risk_state"), Some("missing_risk_state:is_st;is_kcb|allow_buy"),
|
||||||
|
Some("missing_risk_state:unknown_fact"), Some("missing_risk_state:IS_PAUSED")] {
|
||||||
|
candidate.risk_level_code = code.map(str::to_owned);
|
||||||
|
assert_eq!(ChinaAShareRiskControl::selection_rejection_decision_with_config(
|
||||||
|
date, &candidate, &snapshot, Some(&instrument), &config), None);
|
||||||
|
}
|
||||||
|
candidate.risk_level_code = None;
|
||||||
|
assert_eq!(ChinaAShareRiskControl::buy_rejection_reason_with_config(
|
||||||
|
date, &candidate, &snapshot, None, 0.9, &config), Some("paused"));
|
||||||
|
assert_eq!(ChinaAShareRiskControl::sell_rejection_reason_with_config(
|
||||||
|
date, &candidate, &snapshot, None, None, 0.9, &config), Some("paused"));
|
||||||
|
let mut blacklist_only = config;
|
||||||
|
blacklist_only.static_rules.blacklisted_symbols.insert(candidate.symbol.to_string());
|
||||||
|
assert!(blacklist_only.static_rules.selection_checks_enabled());
|
||||||
|
assert_eq!(ChinaAShareRiskControl::selection_rejection_reason_with_config(
|
||||||
|
date, &candidate, &snapshot, None, &blacklist_only), Some("blacklisted"));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn one_yuan_buy_rule_uses_execution_price_not_later_close_or_earlier_open() {
|
fn one_yuan_buy_rule_uses_execution_price_not_later_close_or_earlier_open() {
|
||||||
let day = d(2025, 2, 6);
|
let day = d(2025, 2, 6);
|
||||||
|
|||||||
@@ -0,0 +1,588 @@
|
|||||||
|
{
|
||||||
|
"schema": "fidc.selection-risk-plan-acceptance/v1",
|
||||||
|
"rows": [
|
||||||
|
{
|
||||||
|
"name": "control-1",
|
||||||
|
"receiptSha256": "f18b3b484d40e2a813bd795cb38e263ff43f65b17f31004786d3a23a6af5bcb6",
|
||||||
|
"wallSeconds": 30.986483575077727,
|
||||||
|
"engineSeconds": 8.79,
|
||||||
|
"dataSeconds": 8.445,
|
||||||
|
"validationSeconds": 12.244,
|
||||||
|
"resultSeconds": 1.292,
|
||||||
|
"maxRssKiB": 7090392,
|
||||||
|
"fills": 21393,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 93895,
|
||||||
|
"sha256": "3f089cbcc5412e07bbe2308d0dd60ac561a119f0a2228010fc3323714fde8ca7",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 21555,
|
||||||
|
"sha256": "8c839c89191d2b5220fa1dd86f8d74bdd57fa566a096a0bbf6932d0247b48e8a"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "f928695650bdd90eb25d2acd478e0064046883649efa25cd2d4cdbbd27035c27"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 21393,
|
||||||
|
"sha256": "2a90bef0994dda1b7f6e914e4c58037ec0b91cd828eb09745f71aecde071f791"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 28353,
|
||||||
|
"sha256": "799371917e516fb251b4afb60aeb4a1b8fc4b269ecfc27f827a3b388c4985a04"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 21491,
|
||||||
|
"sha256": "0685ac0c31933b6cf5d1319912de3f398c40ce7ee01c28b4abec1b98f92fb318"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 78,
|
||||||
|
"sha256": "e394cc9e8f3bac17a2f80f9db8738b91d4e960ff230647e17e5145b86d14b986"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "1905f0c8a887215279342b26d5769a6cbe40058971eef15adf86ef2eaa02aeb9",
|
||||||
|
"verifiedFactBlocks": 290,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "control-2",
|
||||||
|
"receiptSha256": "8e5f7f8fe77ba2a798056306277a4ae4f00b6aa98b8c277269aca8c235bbd0fb",
|
||||||
|
"wallSeconds": 13.274638780159876,
|
||||||
|
"engineSeconds": 6.739,
|
||||||
|
"dataSeconds": 5.19,
|
||||||
|
"validationSeconds": 0.209,
|
||||||
|
"resultSeconds": 1.003,
|
||||||
|
"maxRssKiB": 7092040,
|
||||||
|
"fills": 21393,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 93895,
|
||||||
|
"sha256": "3f089cbcc5412e07bbe2308d0dd60ac561a119f0a2228010fc3323714fde8ca7",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 21555,
|
||||||
|
"sha256": "8c839c89191d2b5220fa1dd86f8d74bdd57fa566a096a0bbf6932d0247b48e8a"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "f928695650bdd90eb25d2acd478e0064046883649efa25cd2d4cdbbd27035c27"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 21393,
|
||||||
|
"sha256": "2a90bef0994dda1b7f6e914e4c58037ec0b91cd828eb09745f71aecde071f791"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 28353,
|
||||||
|
"sha256": "799371917e516fb251b4afb60aeb4a1b8fc4b269ecfc27f827a3b388c4985a04"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 21491,
|
||||||
|
"sha256": "0685ac0c31933b6cf5d1319912de3f398c40ce7ee01c28b4abec1b98f92fb318"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 78,
|
||||||
|
"sha256": "e394cc9e8f3bac17a2f80f9db8738b91d4e960ff230647e17e5145b86d14b986"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "1905f0c8a887215279342b26d5769a6cbe40058971eef15adf86ef2eaa02aeb9",
|
||||||
|
"verifiedFactBlocks": 290,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "control-3",
|
||||||
|
"receiptSha256": "d106ddae57c64f931e196b80ffa517443e5c0f11eb9c2079f84d55b2d693fb13",
|
||||||
|
"wallSeconds": 13.043757867999375,
|
||||||
|
"engineSeconds": 6.732,
|
||||||
|
"dataSeconds": 5.159,
|
||||||
|
"validationSeconds": 0.005,
|
||||||
|
"resultSeconds": 1,
|
||||||
|
"maxRssKiB": 7089984,
|
||||||
|
"fills": 21393,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 93895,
|
||||||
|
"sha256": "3f089cbcc5412e07bbe2308d0dd60ac561a119f0a2228010fc3323714fde8ca7",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 21555,
|
||||||
|
"sha256": "8c839c89191d2b5220fa1dd86f8d74bdd57fa566a096a0bbf6932d0247b48e8a"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "f928695650bdd90eb25d2acd478e0064046883649efa25cd2d4cdbbd27035c27"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 21393,
|
||||||
|
"sha256": "2a90bef0994dda1b7f6e914e4c58037ec0b91cd828eb09745f71aecde071f791"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 28353,
|
||||||
|
"sha256": "799371917e516fb251b4afb60aeb4a1b8fc4b269ecfc27f827a3b388c4985a04"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 21491,
|
||||||
|
"sha256": "0685ac0c31933b6cf5d1319912de3f398c40ce7ee01c28b4abec1b98f92fb318"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 78,
|
||||||
|
"sha256": "e394cc9e8f3bac17a2f80f9db8738b91d4e960ff230647e17e5145b86d14b986"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "1905f0c8a887215279342b26d5769a6cbe40058971eef15adf86ef2eaa02aeb9",
|
||||||
|
"verifiedFactBlocks": 290,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "candidate-1",
|
||||||
|
"receiptSha256": "a76e11c115ad42389dfdf72ed674ad75af8ec3d4646feb57feee9e6a4418f20d",
|
||||||
|
"wallSeconds": 12.976857921108603,
|
||||||
|
"engineSeconds": 6.682,
|
||||||
|
"dataSeconds": 5.132,
|
||||||
|
"validationSeconds": 0.004,
|
||||||
|
"resultSeconds": 1.021,
|
||||||
|
"maxRssKiB": 7091752,
|
||||||
|
"fills": 21393,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 93895,
|
||||||
|
"sha256": "3f089cbcc5412e07bbe2308d0dd60ac561a119f0a2228010fc3323714fde8ca7",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 21555,
|
||||||
|
"sha256": "8c839c89191d2b5220fa1dd86f8d74bdd57fa566a096a0bbf6932d0247b48e8a"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "f928695650bdd90eb25d2acd478e0064046883649efa25cd2d4cdbbd27035c27"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 21393,
|
||||||
|
"sha256": "2a90bef0994dda1b7f6e914e4c58037ec0b91cd828eb09745f71aecde071f791"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 28353,
|
||||||
|
"sha256": "799371917e516fb251b4afb60aeb4a1b8fc4b269ecfc27f827a3b388c4985a04"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 21491,
|
||||||
|
"sha256": "0685ac0c31933b6cf5d1319912de3f398c40ce7ee01c28b4abec1b98f92fb318"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 78,
|
||||||
|
"sha256": "e394cc9e8f3bac17a2f80f9db8738b91d4e960ff230647e17e5145b86d14b986"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "1905f0c8a887215279342b26d5769a6cbe40058971eef15adf86ef2eaa02aeb9",
|
||||||
|
"verifiedFactBlocks": 290,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "candidate-2",
|
||||||
|
"receiptSha256": "38f61fd0d495daa5e29d6354679ce51e33473fb3ecbbb420c93d2fd41b74246f",
|
||||||
|
"wallSeconds": 12.927155625075102,
|
||||||
|
"engineSeconds": 6.64,
|
||||||
|
"dataSeconds": 5.128,
|
||||||
|
"validationSeconds": 0.005,
|
||||||
|
"resultSeconds": 1.01,
|
||||||
|
"maxRssKiB": 7092320,
|
||||||
|
"fills": 21393,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 93895,
|
||||||
|
"sha256": "3f089cbcc5412e07bbe2308d0dd60ac561a119f0a2228010fc3323714fde8ca7",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 21555,
|
||||||
|
"sha256": "8c839c89191d2b5220fa1dd86f8d74bdd57fa566a096a0bbf6932d0247b48e8a"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "f928695650bdd90eb25d2acd478e0064046883649efa25cd2d4cdbbd27035c27"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 21393,
|
||||||
|
"sha256": "2a90bef0994dda1b7f6e914e4c58037ec0b91cd828eb09745f71aecde071f791"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 28353,
|
||||||
|
"sha256": "799371917e516fb251b4afb60aeb4a1b8fc4b269ecfc27f827a3b388c4985a04"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 21491,
|
||||||
|
"sha256": "0685ac0c31933b6cf5d1319912de3f398c40ce7ee01c28b4abec1b98f92fb318"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 78,
|
||||||
|
"sha256": "e394cc9e8f3bac17a2f80f9db8738b91d4e960ff230647e17e5145b86d14b986"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "1905f0c8a887215279342b26d5769a6cbe40058971eef15adf86ef2eaa02aeb9",
|
||||||
|
"verifiedFactBlocks": 290,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "candidate-3",
|
||||||
|
"receiptSha256": "9b56896d6dc048c5dd3d56cbe863778122b5bdf42fc9769eaa41f2d1b339dcd4",
|
||||||
|
"wallSeconds": 12.926160736009479,
|
||||||
|
"engineSeconds": 6.664,
|
||||||
|
"dataSeconds": 5.113,
|
||||||
|
"validationSeconds": 0.006,
|
||||||
|
"resultSeconds": 1.006,
|
||||||
|
"maxRssKiB": 7091128,
|
||||||
|
"fills": 21393,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 93895,
|
||||||
|
"sha256": "3f089cbcc5412e07bbe2308d0dd60ac561a119f0a2228010fc3323714fde8ca7",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 21555,
|
||||||
|
"sha256": "8c839c89191d2b5220fa1dd86f8d74bdd57fa566a096a0bbf6932d0247b48e8a"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "f928695650bdd90eb25d2acd478e0064046883649efa25cd2d4cdbbd27035c27"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 21393,
|
||||||
|
"sha256": "2a90bef0994dda1b7f6e914e4c58037ec0b91cd828eb09745f71aecde071f791"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 28353,
|
||||||
|
"sha256": "799371917e516fb251b4afb60aeb4a1b8fc4b269ecfc27f827a3b388c4985a04"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 21491,
|
||||||
|
"sha256": "0685ac0c31933b6cf5d1319912de3f398c40ce7ee01c28b4abec1b98f92fb318"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 78,
|
||||||
|
"sha256": "e394cc9e8f3bac17a2f80f9db8738b91d4e960ff230647e17e5145b86d14b986"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "1905f0c8a887215279342b26d5769a6cbe40058971eef15adf86ef2eaa02aeb9",
|
||||||
|
"verifiedFactBlocks": 290,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "trend-40-control",
|
||||||
|
"receiptSha256": "305f0ea34b50355661ef9d3583467f7160cfbffd95f03b9e21a631bebc37af64",
|
||||||
|
"wallSeconds": 15.628366323187947,
|
||||||
|
"engineSeconds": 8.199,
|
||||||
|
"dataSeconds": 5.234,
|
||||||
|
"validationSeconds": 0.694,
|
||||||
|
"resultSeconds": 1.33,
|
||||||
|
"maxRssKiB": 7108340,
|
||||||
|
"fills": 29776,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 128192,
|
||||||
|
"sha256": "41209fed4c7a5e385a12e170afef685efae7a3b00137365fe2b9aea015dd7948",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 29968,
|
||||||
|
"sha256": "fa578b86d94a5be9ad192258eb87c9be6a1b356d6713e70ae475b95fd130f61d"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "90f63f3c51c62f0fc0abb317a29ac48aa0ead6035d5f75d650a948c33ae1e9b3"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 29776,
|
||||||
|
"sha256": "6626ea78cfaa5d88040496c575be63cd8b573d48d1afe6812579762bf7e2abd0"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 37367,
|
||||||
|
"sha256": "491b32468148cc62779f4c01cee96e4dcf18ce1a6115ccecc437b468e49b2ceb"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 29932,
|
||||||
|
"sha256": "565f5a6271a9e1f0fa31f152141c75db0e5f84784e4d4a83b2277b0fd14c45fc"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 124,
|
||||||
|
"sha256": "d170e1704ee5f64a93b71cecf2178b062d30368df8f5da53c07416b8e8a9c5e5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "ab29a9f999a6b41330255ba82081696a9826825fa6d34941247332adac65249e",
|
||||||
|
"verifiedFactBlocks": 293,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "trend-40-candidate",
|
||||||
|
"receiptSha256": "0174941bea20079730c019b3de4185cc439528160ab54cafc1be4e3f8a0a08fc",
|
||||||
|
"wallSeconds": 14.82603678200394,
|
||||||
|
"engineSeconds": 8.087,
|
||||||
|
"dataSeconds": 5.276,
|
||||||
|
"validationSeconds": 0.004,
|
||||||
|
"resultSeconds": 1.322,
|
||||||
|
"maxRssKiB": 7108656,
|
||||||
|
"fills": 29776,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 128192,
|
||||||
|
"sha256": "41209fed4c7a5e385a12e170afef685efae7a3b00137365fe2b9aea015dd7948",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 29968,
|
||||||
|
"sha256": "fa578b86d94a5be9ad192258eb87c9be6a1b356d6713e70ae475b95fd130f61d"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "90f63f3c51c62f0fc0abb317a29ac48aa0ead6035d5f75d650a948c33ae1e9b3"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 29776,
|
||||||
|
"sha256": "6626ea78cfaa5d88040496c575be63cd8b573d48d1afe6812579762bf7e2abd0"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 37367,
|
||||||
|
"sha256": "491b32468148cc62779f4c01cee96e4dcf18ce1a6115ccecc437b468e49b2ceb"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 29932,
|
||||||
|
"sha256": "565f5a6271a9e1f0fa31f152141c75db0e5f84784e4d4a83b2277b0fd14c45fc"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 124,
|
||||||
|
"sha256": "d170e1704ee5f64a93b71cecf2178b062d30368df8f5da53c07416b8e8a9c5e5"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "ab29a9f999a6b41330255ba82081696a9826825fa6d34941247332adac65249e",
|
||||||
|
"verifiedFactBlocks": 293,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pullback-40-control",
|
||||||
|
"receiptSha256": "0d39c6af608d3ec89fc44d0715dab41229511c68cf5ea4eb01f763c10bded8bf",
|
||||||
|
"wallSeconds": 13.775856785941869,
|
||||||
|
"engineSeconds": 7.374,
|
||||||
|
"dataSeconds": 4.893,
|
||||||
|
"validationSeconds": 0.005,
|
||||||
|
"resultSeconds": 1.358,
|
||||||
|
"maxRssKiB": 7119352,
|
||||||
|
"fills": 31862,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 135630,
|
||||||
|
"sha256": "49fdbd74245d7aa678f1a4851add29f7b12dde71fd50c93c070fd2ee57f35285",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 32010,
|
||||||
|
"sha256": "9be3914d28d7766f12bac45227d2c2da47d61a921f9b918a4b11447da4b78baa"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "2044627b1152c4a2ad8ea92dca3351322d41cfc18c002cda93f274bd810efdad"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 31862,
|
||||||
|
"sha256": "b33d1b4b0f7f86c96c082c217c9a27d86830ccac0de5a33714104ac4756df8d7"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 38679,
|
||||||
|
"sha256": "a45b516a926c57b6c7827f8f1684b6e749d26118b8c5d8e8614afbb23cd87559"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 31966,
|
||||||
|
"sha256": "73704496ab17d10d9a602429d97b728cf22d0896f2d467b0f2064f2f48bf04fb"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 88,
|
||||||
|
"sha256": "2c8de7dbb11c7ca5ac678c17feabec0bd98aac0a031bbb4780eddaa144933293"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "ff32f177e5e0ec4b4f3f0597b61174efdafac77b4f36e6065448b6e9c414f07e",
|
||||||
|
"verifiedFactBlocks": 281,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "pullback-40-candidate",
|
||||||
|
"receiptSha256": "3f0ec7b8b6ad74fc7349586a8716d45b8075ebad03c77776ca78fab5188d49ee",
|
||||||
|
"wallSeconds": 13.927610703045502,
|
||||||
|
"engineSeconds": 7.239,
|
||||||
|
"dataSeconds": 5.137,
|
||||||
|
"validationSeconds": 0.003,
|
||||||
|
"resultSeconds": 1.368,
|
||||||
|
"maxRssKiB": 7119784,
|
||||||
|
"fills": 31862,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 135630,
|
||||||
|
"sha256": "49fdbd74245d7aa678f1a4851add29f7b12dde71fd50c93c070fd2ee57f35285",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 32010,
|
||||||
|
"sha256": "9be3914d28d7766f12bac45227d2c2da47d61a921f9b918a4b11447da4b78baa"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "2044627b1152c4a2ad8ea92dca3351322d41cfc18c002cda93f274bd810efdad"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 31862,
|
||||||
|
"sha256": "b33d1b4b0f7f86c96c082c217c9a27d86830ccac0de5a33714104ac4756df8d7"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 38679,
|
||||||
|
"sha256": "a45b516a926c57b6c7827f8f1684b6e749d26118b8c5d8e8614afbb23cd87559"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 31966,
|
||||||
|
"sha256": "73704496ab17d10d9a602429d97b728cf22d0896f2d467b0f2064f2f48bf04fb"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 88,
|
||||||
|
"sha256": "2c8de7dbb11c7ca5ac678c17feabec0bd98aac0a031bbb4780eddaa144933293"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "ff32f177e5e0ec4b4f3f0597b61174efdafac77b4f36e6065448b6e9c414f07e",
|
||||||
|
"verifiedFactBlocks": 281,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "volume-momentum-80-control",
|
||||||
|
"receiptSha256": "98239365828453888930a1fceb2a7d9b5402b03cd32c9303a9fa1532af3644ed",
|
||||||
|
"wallSeconds": 18.176081838086247,
|
||||||
|
"engineSeconds": 11.154,
|
||||||
|
"dataSeconds": 4.585,
|
||||||
|
"validationSeconds": 0.004,
|
||||||
|
"resultSeconds": 2.268,
|
||||||
|
"maxRssKiB": 7158556,
|
||||||
|
"fills": 51300,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 234267,
|
||||||
|
"sha256": "4359817bb1fbd73b02c2c3456e1f0b7ee7428b090529393bd203e8212979a1dc",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 51696,
|
||||||
|
"sha256": "ca4d333cc4768ec4b528475d1833809c7e76a80de937c635e7e933a0f18264c6"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "31865ccfeb71d260757979524a679880070d691c09083c82865c3de6dd47e440"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 51300,
|
||||||
|
"sha256": "4f45cc0906b6cd02af9ce12450a52f509f6e80e9b26157695ae04e90ce7ca9ac"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 78078,
|
||||||
|
"sha256": "79098ebfa48dcd24b00ba4d19917c291adb80a129b4d90ee1087b5f2210c43aa"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 51783,
|
||||||
|
"sha256": "340699c5d04407c5c6f71dc39c41ac2baedc096bb11185f1ccb99ab7100ba8f8"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 385,
|
||||||
|
"sha256": "2aa0a4d6e6078dbea815b536ce0ee8f6ca03f9c44f63cdfecf4e37a0ff9cf561"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "5748fe4db08f8d81607622b302cc43c1d2e4ef50c3b87739fb6c20cd40de79c0",
|
||||||
|
"verifiedFactBlocks": 309,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "volume-momentum-80-candidate",
|
||||||
|
"receiptSha256": "1cbbccd9678bc8ea2754f2ffa678f3d43feb659a58f86393c4c54961daa5a8d0",
|
||||||
|
"wallSeconds": 18.627057212870568,
|
||||||
|
"engineSeconds": 11.013,
|
||||||
|
"dataSeconds": 5.2,
|
||||||
|
"validationSeconds": 0.005,
|
||||||
|
"resultSeconds": 2.267,
|
||||||
|
"maxRssKiB": 7152664,
|
||||||
|
"fills": 51300,
|
||||||
|
"canonical": {
|
||||||
|
"schemaVersion": "fidc-canonical-backtest-result/v2",
|
||||||
|
"algorithm": "sha256",
|
||||||
|
"ordering": "engine_fact_order_v2",
|
||||||
|
"totalRows": 234267,
|
||||||
|
"sha256": "4359817bb1fbd73b02c2c3456e1f0b7ee7428b090529393bd203e8212979a1dc",
|
||||||
|
"sections": {
|
||||||
|
"accountEvents": {
|
||||||
|
"rowCount": 51696,
|
||||||
|
"sha256": "ca4d333cc4768ec4b528475d1833809c7e76a80de937c635e7e933a0f18264c6"
|
||||||
|
},
|
||||||
|
"equityFacts": {
|
||||||
|
"rowCount": 1025,
|
||||||
|
"sha256": "31865ccfeb71d260757979524a679880070d691c09083c82865c3de6dd47e440"
|
||||||
|
},
|
||||||
|
"fillEvents": {
|
||||||
|
"rowCount": 51300,
|
||||||
|
"sha256": "4f45cc0906b6cd02af9ce12450a52f509f6e80e9b26157695ae04e90ce7ca9ac"
|
||||||
|
},
|
||||||
|
"holdingSnapshots": {
|
||||||
|
"rowCount": 78078,
|
||||||
|
"sha256": "79098ebfa48dcd24b00ba4d19917c291adb80a129b4d90ee1087b5f2210c43aa"
|
||||||
|
},
|
||||||
|
"orderEvents": {
|
||||||
|
"rowCount": 51783,
|
||||||
|
"sha256": "340699c5d04407c5c6f71dc39c41ac2baedc096bb11185f1ccb99ab7100ba8f8"
|
||||||
|
},
|
||||||
|
"riskAudits": {
|
||||||
|
"rowCount": 385,
|
||||||
|
"sha256": "2aa0a4d6e6078dbea815b536ce0ee8f6ca03f9c44f63cdfecf4e37a0ff9cf561"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"storeSha256": "5748fe4db08f8d81607622b302cc43c1d2e4ef50c3b87739fb6c20cd40de79c0",
|
||||||
|
"verifiedFactBlocks": 309,
|
||||||
|
"sharedInputsUnchanged": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"sharedInputFiles": 9257,
|
||||||
|
"sharedInputBytes": 12596608049,
|
||||||
|
"sharedInputInventorySha256": "1a4818aaab906e77b750e28601d3d405ad9e14e0553f7937cc60b68be0c9b71d",
|
||||||
|
"verifiedFactBlocks": 3506,
|
||||||
|
"status": "candidate-not-deployed",
|
||||||
|
"sourceCommit": "d5b682c6d09704ff23d725a8dd8b155db3eb6967",
|
||||||
|
"engineCommit": "d2aa16a2f0064297d0d8c931060646d66422e9d4",
|
||||||
|
"serviceCommit": "4e23c7558d8301ba697543c39d5604289bb82c53",
|
||||||
|
"controlRunnerSha256": "b90886b80634c7565ca215fbe1f9ed0cbb5a6bd967373a9b1f6753be5164737d",
|
||||||
|
"candidateRunnerSha256": "1bda2d3acc016ca5addbb12e33cfcc31a23ece562f1d7d1ff8a825fbc83873fb",
|
||||||
|
"candidateApiSha256": "30ac3b50996e1769c1d93bd5d302a23c4af7ebe773d3e8110ee278c44aeb9501",
|
||||||
|
"bounds": [
|
||||||
|
"All twelve are new runner processes and private result artifacts using the same verified shared input files.",
|
||||||
|
"Input hashing is outside the elapsed benchmark timer; no GDB samples are in these measurements.",
|
||||||
|
"The first control had 12.244s Source validation and a slower preparation phase. Its entire latency difference is not candidate speedup.",
|
||||||
|
"The full input set is identical across the twelve runs, not only a global cache hit counter.",
|
||||||
|
"No Source/trading service was changed and no paused research/signal task resumed.",
|
||||||
|
"The independently recorded intraday-clock counterexample remains open. These day-level replays do not close it."
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# 日内时钟与手工回放前置问题
|
||||||
|
|
||||||
|
2026-09-14。本轮只有未提交的失败回归,未修改引擎实现,未部署。
|
||||||
|
|
||||||
|
## 已复现的精确反例
|
||||||
|
|
||||||
|
`engine::tests::minute_observer_never_sees_a_later_fill_from_a_coarse_phase`使用实际BacktestEngine/BrokerSimulator测试入口、同一证券及合法测试日行情。开盘竞价回调生成100股限价10.0的委托,全天存在09:30、10:00、10:15、13:00、13:01报价,后续分钟回调读取真实模拟账本。
|
||||||
|
|
||||||
|
- CurrentBarClose/09:30窗口:10:15成交;10:00观察为0股,通过。
|
||||||
|
- NextBarOpen/一天信号滞后/09:30窗口:10:15成交;10:00观察为0股,通过。
|
||||||
|
- CurrentBarClose/13:00窗口:实际FillEvent时间13:00、数量100,但09:30、10:00、10:15回调均已观察到100股,失败。完整观察序列为`[(09:30,100),(10:00,100),(10:15,100),(13:00,100),(13:01,100)]`,不是仅日志显示错误。
|
||||||
|
|
||||||
|
根因路径是粗粒度auction/on_day阶段调用broker时使用未来的全局intraday_execution_start_time,先将13:00成交写进PortfolioState,随后引擎才从09:30开始遍历分钟事件。正常09:30路径已有边界,不能因为一次测试通过就断言所有时点安全,也不能把所有粗粒度调用一概认定有问题。
|
||||||
|
|
||||||
|
首次盘前调度夹具没有产生订单,因此不作为时钟证据;改用明确返回委托的open_auction回调完成上述复现。盘前on_scheduled普通委托是否被忽略应另行核对其正式合同,不能当空成功。
|
||||||
|
|
||||||
|
## 必须按真实执行时序修复
|
||||||
|
|
||||||
|
不能删掉早间回调或给显示持仓做遮掩。需要使已生成的未来执行意图、待执行批次、订单回报、策略回调、手工意图及实际投影按执行时钟前进;保留独立信号日与数据可见性。不能仅把新订单延迟却让依赖持仓的后续策略回调仍提前计算。
|
||||||
|
|
||||||
|
需覆盖当前/下一开盘、显式时间和默认收盘、限价/市价/算法单、部分成交及取消、股票池卖后续买、跨日/T+1、0%人工覆盖和恢复。已有真实回放与六类Canonical必须按各自合同核对,不能用收益接近或单个对照替代。
|
||||||
|
|
||||||
|
当前失败回归保留在`crates/fidc-core/src/engine.rs`未提交工作树,属于本任务,不删除、不忽略、不发布成绿色测试。下一步直接修复并扩充该回归,再进入逐笔手工回放;不要重新检查已完成的页头或流式消息。
|
||||||
|
|
||||||
|
Live取消请求另有待核对项:`CancelRequested`当前在网关返回后才持久化,不能不加说明就把回报时间当最初请求时间。完整手工回放需要验证并补齐真实意图/提交/成交/取消关联,当前生产手工影子仍保持明确拒绝纯比例模拟。
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
# Selection Risk Plan Performance
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Candidate tested, not deployed. The change removes selection calls that have
|
||||||
|
no possible effect under the current frozen policy. It does not disable any
|
||||||
|
configured rule, execution-day check or strategy expression. Engine time falls
|
||||||
|
slightly in the measured cases; this is not the solution to the main remaining
|
||||||
|
data construction cost and is not a general whole-backtest speedup claim.
|
||||||
|
|
||||||
|
The independent [intraday-clock counterexample](intraday-clock-causality-20260914.md)
|
||||||
|
remains open. This work does not remove that test or its evidence, change the
|
||||||
|
execution clock, or turn day-level parity into full framework acceptance.
|
||||||
|
The published service stays at e81bf47/c98bcc3. Source d5b682c6 remains frozen;
|
||||||
|
research and signal work stay paused. No trading operation was submitted.
|
||||||
|
|
||||||
|
## Evidence Leading to the Change
|
||||||
|
|
||||||
|
The official HTTP diagnostic replay btr_1789322878865_2871869_0 preserved the
|
||||||
|
original canonical and result-store SHA. Ten bounded Boris-only GDB snapshots
|
||||||
|
showed source inventory, PreparedDayBuilder, factor normalization and price
|
||||||
|
series construction, followed by repeated selection risk calls. GDB pauses are
|
||||||
|
not normal performance measurements and snapshot counts are not flamegraph
|
||||||
|
percentages. Source/target PID, binary SHA and CPU/thread resources stayed fixed.
|
||||||
|
|
||||||
|
The diagnostic helper now shares the existing canonical executable policy with
|
||||||
|
the saved-run profiler: it accepts both audited build roots and immutable API
|
||||||
|
release directories, but not arbitrary paths. Seven related tests passed.
|
||||||
|
|
||||||
|
## Implementation and Correctness
|
||||||
|
|
||||||
|
StaticRiskRuleConfig reports whether selection has an enabled state rule or an
|
||||||
|
enabled nonempty blacklist. The strategy computes this once before iterating
|
||||||
|
candidate symbols. If no such rule exists, the old selection function would
|
||||||
|
always return None, so that no-op call is omitted. Explicit universe conditions,
|
||||||
|
market/factor checks and all buy/sell execution paths are unchanged.
|
||||||
|
|
||||||
|
The ten state flags are also shared with the existing missing-risk-state checks
|
||||||
|
to avoid maintaining three separate flag lists. Blacklist presence is kept
|
||||||
|
separate: a blacklist is not missing market-risk data. No cross-strategy cache,
|
||||||
|
strategy identifier, fixed date, trading time or account state is introduced.
|
||||||
|
|
||||||
|
Tests enumerate all 4,096 combinations of ten selection flags and blacklist
|
||||||
|
enabled/populated states. The flag list is checked against the serialized
|
||||||
|
configuration, so adding a selection field requires updating the activation
|
||||||
|
test. Further tests retain missing-state behavior and show that paused buys
|
||||||
|
and sells remain rejected when selection checks are inactive.
|
||||||
|
|
||||||
|
On 177: 805 core unit/integration tests passed (9 ignored), 448 runner tests
|
||||||
|
passed (9 ignored), 119 API tests passed (5 ignored), and 28 benchmark/profiler
|
||||||
|
tests passed. These counts do not resolve the independently recorded clock
|
||||||
|
failure, which is not part of this frozen committed test tree.
|
||||||
|
|
||||||
|
## Reproducible Shared-Input Method
|
||||||
|
|
||||||
|
Each of the twelve replays has a new process and a new private result root.
|
||||||
|
The official runner benchmark gained --shared-runtime-cache. It resolves the
|
||||||
|
explicit cache root from the declared Boris service, requires canonical private
|
||||||
|
storage, hashes existing inputs before and after, and refuses any changed or
|
||||||
|
removed original. This mode cannot invoke copied-input disposal.
|
||||||
|
|
||||||
|
All twelve runs used the same 9,257 files / 12,596,608,049 bytes. Their complete
|
||||||
|
input inventories, file identities and byte SHA values are equal. No new Arrow
|
||||||
|
or binary cache input appeared. No backtest result was reused. Hash preparation
|
||||||
|
and verification are outside the measured runner interval; this is a shared
|
||||||
|
warm-input test, not raw-disk cold IO. Unlike the earlier copied-cache method,
|
||||||
|
it does not allocate another approximately 2 GB per replay on the nearly full
|
||||||
|
SSD. Original inputs and every result remain intact.
|
||||||
|
|
||||||
|
The common execution interval is 2021-08-23 through 2025-11-17 with 10,000,000
|
||||||
|
initial cash and each case's unchanged frozen strategy/bundle. This is not five
|
||||||
|
complete execution years. CPU affinity and 8 Rayon / 16 Tokio threads match the
|
||||||
|
declared reference service; no global resource limit was increased.
|
||||||
|
|
||||||
|
## Measurements
|
||||||
|
|
||||||
|
| Case | Wall seconds | Source validation | Data preparation | Engine |
|
||||||
|
|---|---:|---:|---:|---:|
|
||||||
|
| Rotation control 1 | 30.986 | 12.244 | 8.445 | 8.790 |
|
||||||
|
| Rotation candidate 1 | 12.977 | 0.004 | 5.132 | 6.682 |
|
||||||
|
| Rotation control 2 | 13.275 | 0.209 | 5.190 | 6.739 |
|
||||||
|
| Rotation candidate 2 | 12.927 | 0.005 | 5.128 | 6.640 |
|
||||||
|
| Rotation candidate 3 | 12.926 | 0.006 | 5.113 | 6.664 |
|
||||||
|
| Rotation control 3 | 13.044 | 0.005 | 5.159 | 6.732 |
|
||||||
|
| Trend 40 control | 15.628 | 0.694 | 5.234 | 8.199 |
|
||||||
|
| Trend 40 candidate | 14.826 | 0.004 | 5.276 | 8.087 |
|
||||||
|
| Pullback 40 control | 13.776 | 0.005 | 4.893 | 7.374 |
|
||||||
|
| Pullback 40 candidate | 13.928 | 0.003 | 5.137 | 7.239 |
|
||||||
|
| Volume momentum 80 control | 18.176 | 0.004 | 4.585 | 11.154 |
|
||||||
|
| Volume momentum 80 candidate | 18.627 | 0.005 | 5.200 | 11.013 |
|
||||||
|
|
||||||
|
Rotation engine medians are 6.739 versus 6.664 seconds, approximately 1.1%.
|
||||||
|
The other paired engine reductions are approximately 1.4%, 1.8% and 1.3%.
|
||||||
|
These are small CPU-path improvements. Pullback and volume total latency did
|
||||||
|
not improve because their preparation times were higher. The first control's
|
||||||
|
Source wait and unexplained slower construction are recorded, not attributed
|
||||||
|
to this code or discarded to manufacture a large speedup. Peak RSS stays about
|
||||||
|
6.76-6.83 GiB; there is no significant memory reduction claim.
|
||||||
|
|
||||||
|
Each case matches its independent prior baseline for all six canonical
|
||||||
|
sections and store bytes: 21,393 / 29,776 / 31,862 / 51,300 fills. Result receipts,
|
||||||
|
runtime/strategy identities, physical manifests and 3,506 fact blocks were
|
||||||
|
verified. The shared input inventory SHA is in the acceptance record. Full
|
||||||
|
unaltered receipts remain on 177; the repository stores the compact verified
|
||||||
|
summary rather than repeating the 9,257-file inventory in every document.
|
||||||
|
|
||||||
|
## Remaining Work
|
||||||
|
|
||||||
|
Prioritize direct typed-column reuse during daily snapshot and DataSet
|
||||||
|
construction; approximately five seconds of preparation remain in these warm
|
||||||
|
cases. Do not skip normalization, NULL, adjustment or date/uniqueness checks.
|
||||||
|
Source cold-query and contract-validation latency remain separate tasks under
|
||||||
|
the Source freeze. The earlier cache-boundary candidate still needs its missing
|
||||||
|
cold/same-window acceptance, and this combined candidate has no HTTP publication
|
||||||
|
gate yet. Financial PIT, minute-clock behavior, signal lifecycle and UI factor
|
||||||
|
condition acceptance are not claimed complete.
|
||||||
|
|
||||||
|
- Candidate engine: d2aa16a2f0064297d0d8c931060646d66422e9d4.
|
||||||
|
- Candidate service source: 4e23c7558d8301ba697543c39d5604289bb82c53.
|
||||||
|
- Control runner SHA: b90886b80634c7565ca215fbe1f9ed0cbb5a6bd967373a9b1f6753be5164737d.
|
||||||
|
- Candidate runner SHA: 1bda2d3acc016ca5addbb12e33cfcc31a23ece562f1d7d1ff8a825fbc83873fb.
|
||||||
|
- Candidate API SHA: 30ac3b50996e1769c1d93bd5d302a23c4af7ebe773d3e8110ee278c44aeb9501.
|
||||||
|
- Evidence root: /srv/fidc/canonical/run/research/selection-risk-plan-20260914.
|
||||||
|
- HTTP diagnostic: /srv/fidc/canonical/run/research/http-phase-profile-20260914.
|
||||||
|
|
||||||
|
[Verified acceptance summary](evidence/selection-risk-plan-20260914/acceptance.json).
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
# 股票池卖出批次与买入续执行
|
# 股票池卖出批次与买入续执行
|
||||||
|
|
||||||
2026-09-13,开发候选,尚未部署。不是完整股票池验收结论。
|
2026-09-13开发,2026-09-14 00:00至00:06 CST完成177配套发布,annotated tag v2026.9.13.16。Engine c98bcc3、Service aa3fe40、Trading b1d402e;不是完整股票池验收结论。
|
||||||
|
|
||||||
## 原问题
|
## 原问题
|
||||||
|
|
||||||
@@ -21,4 +21,8 @@
|
|||||||
|
|
||||||
9项新增专项覆盖未成交卖出续买、部分成交/买单ID、窗口结束、新信号覆盖、发送前新价/日期、缺价拒绝、止盈清仓禁回买、跨日清理和不订阅分钟的完整引擎执行。全工作区803项通过、9项外部/专项忽略单列;配套Trading613通过,Runner本机432通过、9项忽略。完整引擎测试夹具需显式提供每日因子与候选,缺少两者会得到无执行日期,不能据空运行当作成功。
|
9项新增专项覆盖未成交卖出续买、部分成交/买单ID、窗口结束、新信号覆盖、发送前新价/日期、缺价拒绝、止盈清仓禁回买、跨日清理和不订阅分钟的完整引擎执行。全工作区803项通过、9项外部/专项忽略单列;配套Trading613通过,Runner本机432通过、9项忽略。完整引擎测试夹具需显式提供每日因子与候选,缺少两者会得到无执行日期,不能据空运行当作成功。
|
||||||
|
|
||||||
下一步以已推送精确源码构建177隔离Runner,用原两个混合请求、原24只配置和冻结数据包核对逐日目标/委托/成交/持仓及Canonical,再配套发布。优先级仍可在真实资金或仓位约束不足时影响分配,不能预设所有不同排序的结果必须相同。
|
177独立进程对三个原请求分别执行原版和修复版,共六次原生回放;原版各自与原历史Canonical相等,原请求及数据包不变。修复后两种优先级均10成交/4持仓/权益9,706,248.648662,逐股数量、费用、时钟、逐日权益和持仓完全一致(订单ID仍按各自原顺序生成,不伪装为同一Canonical)。原24只回放51成交/21持仓/权益9,685,563.876924999,不强求保留旧54笔:09-08和09-10卖出晚于窗口,未提交买入阶段到期;09-11卖出09:31完成后继续买入。混合样本09-09与09-10同样在窗外不新建买单,09-11在09:34完成卖出后续买,已提交DAY单可在窗口后继续成交。
|
||||||
|
|
||||||
|
生产API三次验收分别为btr_req_6854471517438a896378785b96a81e4ab41f0d77f898bf37、btr_req_0d32c6e07598c16728992374f1800804ad2cd06d85f18d15、btr_req_4ae4ee17bf90bbba5ca579a79c7d4e1c410fc2d4506e5800,均与对应原生候选Canonical相同;旧结果/配置回读保持。未提交券商委托、创建交易任务或改写配置,Source冻结及研究/信号暂停保持。完整逐笔回执在177 /srv/fidc/canonical/run/research/stock-pool-sell-buy-20260913,部署回执/tmp/fidc-sell-buy-api-release-20260913.json与/tmp/fidc-sell-buy-trading-release-20260913.json。
|
||||||
|
|
||||||
|
优先级在真实资金或仓位约束不足时仍可影响分配,不能将本例结论外推所有排序。完整Goal下一项仍是手工委托影子回放、流式日期消息/摘要投影和剩余参数矩阵;不重复此已解决样本。
|
||||||
|
|||||||
Reference in New Issue
Block a user