diff --git a/crates/fidc-core/src/platform_expr_strategy.rs b/crates/fidc-core/src/platform_expr_strategy.rs index edbd980..f63ed67 100644 --- a/crates/fidc-core/src/platform_expr_strategy.rs +++ b/crates/fidc-core/src/platform_expr_strategy.rs @@ -8636,6 +8636,11 @@ impl PlatformExprStrategy { self.stock_state(ctx, date, symbol).map(Some) } + fn unscheduled_explicit_actions_are_due(&self, decision_date: NaiveDate) -> bool { + self.config.signal_rebalance_dates.is_empty() + || self.config.signal_rebalance_dates.contains(&decision_date) + } + fn action_when_matches( &self, ctx: &StrategyContext<'_>, @@ -11679,6 +11684,7 @@ impl Strategy for PlatformExprStrategy { if self.config.explicit_action_stage == PlatformExplicitActionStage::OpenAuction && !self.config.explicit_actions.is_empty() && self.config.explicit_action_schedule.is_none() + && self.unscheduled_explicit_actions_are_due(ctx.decision_date) { return self.explicit_action_decision(ctx); } @@ -11735,6 +11741,7 @@ impl Strategy for PlatformExprStrategy { let (explicit_action_intents, mut explicit_action_diagnostics) = if !in_skip_window && self.config.explicit_action_stage == PlatformExplicitActionStage::OnDay && self.config.explicit_action_schedule.is_none() + && self.unscheduled_explicit_actions_are_due(decision_date) { self.explicit_action_intents(ctx, decision_date, &day)? } else { @@ -23516,6 +23523,33 @@ mod tests { )); } + #[test] + fn signal_date_explicit_actions_are_due_only_on_declared_snapshot_dates() { + let first = d(2025, 2, 3); + let between = d(2025, 2, 4); + let second = d(2025, 2, 5); + let mut config = PlatformExprStrategyConfig::generic(); + config.signal_rebalance_dates = BTreeSet::from([first, second]); + config.explicit_actions = vec![PlatformTradeAction::Order { + kind: PlatformExplicitOrderKind::TargetPercent, + symbol: "000001.SZ".to_string(), + amount_expr: format!( + "if decision_date == \"{first}\" {{ 0.5 }} else if decision_date == \"{second}\" {{ 0.0 }} else {{ 0.0 }}" + ), + limit_price_expr: None, + time_in_force: None, + start_time_expr: None, + end_time_expr: None, + when_expr: None, + reason: "full_target_snapshot".to_string(), + }]; + let strategy = PlatformExprStrategy::new(config); + + assert!(strategy.unscheduled_explicit_actions_are_due(first)); + assert!(!strategy.unscheduled_explicit_actions_are_due(between)); + assert!(strategy.unscheduled_explicit_actions_are_due(second)); + } + #[test] fn platform_explicit_actions_keep_every_declared_trade_time() { let calendar = sample_calendar();