拆分调仓日期与执行时钟
This commit is contained in:
@@ -164,6 +164,16 @@ impl<'a> Scheduler<'a> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Evaluate only the trading-calendar frequency of a rule.
|
||||
///
|
||||
/// Strategy callbacks and order execution clocks are separate contracts:
|
||||
/// a 15:00 schedule is still due on the same daily/weekly/monthly trading
|
||||
/// date even when the engine's coarse `on_day` callback runs at another
|
||||
/// default time. Exact clock matching remains in `triggered_rules_at`.
|
||||
pub fn is_due_on(&self, date: NaiveDate, rule: &ScheduleRule) -> bool {
|
||||
self.matches(date, rule)
|
||||
}
|
||||
|
||||
fn matches(&self, date: NaiveDate, rule: &ScheduleRule) -> bool {
|
||||
match &rule.frequency {
|
||||
ScheduleFrequency::Daily => true,
|
||||
@@ -265,6 +275,29 @@ mod tests {
|
||||
])
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn date_due_is_independent_from_the_order_execution_clock() {
|
||||
let calendar = sample_calendar();
|
||||
let scheduler = Scheduler::new(&calendar);
|
||||
let daily = ScheduleRule::daily("close_signal", ScheduleStage::OnDay)
|
||||
.with_time_rule(ScheduleTimeRule::physical_time(15, 0));
|
||||
|
||||
assert!(scheduler.is_due_on(d(2025, 1, 30), &daily));
|
||||
assert!(scheduler.is_due_on(d(2025, 1, 31), &daily));
|
||||
assert!(scheduler.triggered_rules_at(
|
||||
d(2025, 1, 30),
|
||||
ScheduleStage::OnDay,
|
||||
Some(NaiveTime::from_hms_opt(15, 0, 0).unwrap()),
|
||||
std::slice::from_ref(&daily),
|
||||
).len() == 1);
|
||||
assert!(scheduler.triggered_rules_at(
|
||||
d(2025, 1, 30),
|
||||
ScheduleStage::OnDay,
|
||||
Some(NaiveTime::from_hms_opt(10, 18, 0).unwrap()),
|
||||
std::slice::from_ref(&daily),
|
||||
).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn scheduler_matches_daily_weekly_and_monthly_rules() {
|
||||
let calendar = sample_calendar();
|
||||
|
||||
Reference in New Issue
Block a user