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_time

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Initialize the rollover day (the module's begin/prepare step) before the acknowledgement phase runs.
  2. Acknowledge once per rollover day only; guard the driver against duplicate ack callbacks.
  3. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/90f06abe3a7699ca. Report an issue: GitHub.