Skip to content

fix: guard calendar[index+1] peek in get_step_time for last bar (#2278)#2304

Open
Vedantvijayhumbe wants to merge 1 commit into
microsoft:mainfrom
Vedantvijayhumbe:main
Open

fix: guard calendar[index+1] peek in get_step_time for last bar (#2278)#2304
Vedantvijayhumbe wants to merge 1 commit into
microsoft:mainfrom
Vedantvijayhumbe:main

Conversation

@Vedantvijayhumbe

Copy link
Copy Markdown

fix(backtest): resolve IndexError at the right calendar boundary (#2278)

Description

When end_time falls on the final calendar entry and no future calendar is available, calendar_index + 1 evaluates out of bounds. This results in the backtest crashing with an opaque IndexError.

This PR guards the calendar peek in TradeCalendarManager.get_step_time. The new logic operates as follows:

  • If calendar_index + 1 < len(self._calendar), it uses the next bar as before.
  • Otherwise, it computes the right endpoint as left + one freq-period, which mirrors the day_start + Timedelta(days=1) idiom already used in get_data_cal_range.
  • epsilon_change is then applied to whichever right endpoint is chosen, ensuring the closed-interval convention is preserved across both execution paths.

Motivation and Context

Resolves Issue: Fixes #2278

Previously, backtests traversing the entire dataset would fail on the very last trading step. This change ensures that backtests can safely process the final bar without breaking frequency assumptions or missing final portfolio calculations.

How Has This Been Tested?

  • Pass the test by running: pytest qlib/tests/test_all_pipeline.py under upper directory of qlib.
  • If you are adding a new feature, test on your own test scripts.

Specific Tests Added:
Added tests/backtest/test_calendar_boundary.py which explicitly covers:

  • The last-bar step does not raise an IndexError.
  • Proper calculation of day and minute fallback values.
  • Pre-boundary steps remain completely unchanged.
  • The full backtest loop terminates successfully with the correct step count.

Types of changes

  • Fix bugs
  • Add new feature
  • Update documentation

…osoft#2278)

When end_time falls on the final calendar entry and no future calendar is
available, calendar_index + 1 is out of bounds, crashing the backtest with
an opaque IndexError.

Guard the peek: if calendar_index + 1 < len(self._calendar) use the next bar
as before; otherwise compute the right endpoint as left + one freq-period,
mirroring the day_start + Timedelta(days=1) idiom already used in
get_data_cal_range. epsilon_change is applied to whichever right is chosen,
so the closed-interval convention is preserved on both paths.

Added tests/backtest/test_calendar_boundary.py covering:
- last-bar step does not raise
- day and minute fallback values
- pre-boundary steps are unchanged
- full loop terminates with the correct step count
@Vedantvijayhumbe

Copy link
Copy Markdown
Author

@zhaow-de can you help me with the license/cla

@Vedantvijayhumbe

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Backtest IndexError at the right calendar boundary (get_step_time peeks calendar[index+1])

1 participant