nautechsystems/nautilus_trader · error
FX rollover day is not initialized
Error message
FX rollover day is not initialized
What it means
Raised in the FX rollover module's `acknowledge` (invoked via `process_rollover`) when `self.rollover_day` is None, meaning no rollover day was initialized for the current processing step. Acknowledging outcomes requires an active rollover day holding the pending adjustments batch.
Source
Thrown at crates/backtest/src/modules/fx_rollover.rs:659
}
booking_date = next;
};
let adjustments = batch.iter().map(|adjustment| adjustment.amount).collect();
let mut day = self.rollover_day.borrow_mut();
let day = day.as_mut().expect("rollover day initialized");
day.pending_adjustments = Some(batch);
day.pending_end_date = Some(batch_end_date);
day.attempt_time = Some(ts_now);
Ok(SimulationModuleResult::Completed(adjustments))
}
fn acknowledge(&self, outcomes: &[AccountAdjustmentOutcome]) -> anyhow::Result<()> {
let (adjustments, attempt_time, batch_end_date) = {
let mut day = self.rollover_day.borrow_mut();
let day = day
.as_mut()
.ok_or_else(|| anyhow::anyhow!("FX rollover day is not initialized"))?;
let adjustment_count = day
.pending_adjustments
.as_ref()
.ok_or_else(|| anyhow::anyhow!("no completed FX rollover batch to acknowledge"))?
.len();
anyhow::ensure!(
outcomes.len() == adjustment_count,
"FX rollover acknowledgement count {}, expected {}",
outcomes.len(),
adjustment_count
);
let adjustments = day
.pending_adjustments
.take()
.ok_or_else(|| anyhow::anyhow!("no completed FX rollover batch to acknowledge"))?;
(
adjustments,
day.attempt_timeView on GitHub (pinned to 18893faf8b)
Solutions
- Initialize the rollover day (the module's begin/prepare step) before the acknowledgement phase runs.
- Acknowledge once per rollover day only; guard the driver against duplicate ack callbacks.
- Verify the driver only routes ack events for days where a rollover batch was actually processed.
Example fix
// before
on_ack(|| engine.acknowledge(&outcomes)?);
// after
if engine.rollover_active() {
on_ack(|| engine.acknowledge(&outcomes)?);
} Defensive patterns
Strategy: type-guard
Validate before calling
anyhow::ensure!(engine.rollover_day_initialized(), "FX rollover day must be initialized before acknowledge");
Type guard
fn fx_ack_ready(engine: &FxRolloverModule) -> bool { engine.rollover_day_initialized() } Try / catch
match engine.acknowledge(&outcomes) {
Err(e) if e.to_string().contains("FX rollover day is not initialized") => {
log::warn!("duplicate or out-of-order ack ignored");
}
other => other?,
} Prevention
- Initialize rollover day state each processing day before any ack
- Acknowledge once per rollover batch
- Route ack callbacks only for days where a rollover was processed
When it happens
Trigger: Calling `acknowledge` before the day's rollover was started; acknowledging twice (the first ack consumes the rollover day); running `process_rollover`'s ack phase on a module that never had its day state set.
Common situations: Event-driven drivers where the ack callback fires on days without rollover; tests constructing the module and calling process/ack out of order; reset or re-init between batch generation and acknowledgement.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- no completed FX rollover batch to acknowledge
- CFD swap rollover day is not initialized
- Python SimulationModule.reset failed: {e}
- Active execution intent {intent_id} was not found
- Cannot handle command: {command:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/90f06abe3a7699ca.
Report an issue: GitHub.