import%20marimo%0A%0A__generated_with%20%3D%20%220.25.0%22%0Aapp%20%3D%20marimo.App()%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20marimo%20as%20mo%0A%0A%20%20%20%20return%20(mo%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20METADATA%20%3D%20%7B%0A%20%20%20%20%20%20%20%20%22id%22%3A%20%22rolling_origin_backtesting%22%2C%0A%20%20%20%20%20%20%20%20%22name%22%3A%20%22Rolling-Origin%20Backtesting%22%2C%0A%20%20%20%20%20%20%20%20%22kind%22%3A%20%22concept%22%2C%0A%20%20%20%20%20%20%20%20%22difficulty%22%3A%20%22intermediate%22%2C%0A%20%20%20%20%20%20%20%20%22status%22%3A%20%22complete%22%2C%0A%20%20%20%20%20%20%20%20%22topics%22%3A%20%5B%22forecasting%22%2C%20%22backtesting%22%2C%20%22data_splitting%22%2C%20%22evaluation%22%2C%20%22leakage%22%5D%2C%0A%20%20%20%20%20%20%20%20%22related_models%22%3A%20%5B%22tcn%22%2C%20%22modern_tcn%22%2C%20%22chronos%22%5D%2C%0A%20%20%20%20%20%20%20%20%22prerequisites%22%3A%20%5B%22train_validation_test%22%2C%20%22forecasting_baselines%22%5D%2C%0A%20%20%20%20%7D%0A%0A%20%20%20%20mo.md(f%22%23%20%7BMETADATA%5B'name'%5D%7D%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20In%20one%20sentence%0A%0A%20%20%20%20Rolling-origin%20backtesting%20evaluates%20a%20forecaster%20at%20several%20historical%20cutoff%20dates%20while%20preserving%20the%20direction%20of%20time.%0A%0A%20%20%20%20%23%23%20Why%20one%20split%20is%20fragile%0A%0A%20%20%20%20A%20single%20train%2Ftest%20cutoff%20can%20land%20in%20an%20unusually%20easy%20or%20difficult%20regime.%20Rolling%20the%20forecast%20origin%20forward%20repeats%20the%20decision%20the%20model%20will%20face%20in%20production%3A%20fit%20or%20condition%20on%20the%20past%2C%20predict%20the%20next%20horizon%2C%20reveal%20the%20outcome%2C%20then%20move%20forward.%0A%0A%20%20%20%20Unlike%20shuffled%20cross-validation%2C%20every%20validation%20observation%20remains%20later%20than%20the%20context%20used%20to%20predict%20it.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20%23%23%20Expanding%20and%20sliding%20windows%0A%0A%20%20%20%20With%20an%20**expanding%20window**%2C%20training%20always%20starts%20at%20the%20first%20observation%20and%20grows%20at%20every%20origin.%20This%20uses%20all%20available%20history.%0A%0A%20%20%20%20With%20a%20**sliding%20window**%2C%20the%20start%20moves%20too%2C%20keeping%20a%20fixed%20context%20length.%20This%20can%20be%20better%20when%20old%20regimes%20no%20longer%20describe%20current%20behavior.%0A%0A%20%20%20%20For%20origin%20%24o%24%2C%20context%20length%20%24C%24%2C%20and%20horizon%20%24H%24%3A%0A%0A%20%20%20%20%24%24%0A%20%20%20%20%5Ctext%7Bcontext%7D%3D%5Bo-C%2Co)%2C%20%5Cqquad%20%5Ctext%7Btest%7D%3D%5Bo%2Co%2BH).%0A%20%20%20%20%24%24%0A%0A%20%20%20%20Scaling%2C%20feature%20selection%2C%20and%20hyperparameter%20tuning%20must%20be%20fitted%20inside%20the%20historical%20side%20of%20each%20evaluation%20procedure.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo)%3A%0A%20%20%20%20mo.md(r%22%22%22%0A%20%20%20%20---%0A%0A%20%20%20%20%23%23%20Notebook%20%E2%80%94%20make%20the%20evaluation%20windows%20visible%0A%0A%20%20%20%20The%20safest%20way%20to%20debug%20time-series%20validation%20is%20to%20draw%20the%20exact%20indices%20used%20by%20every%20fold.%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0A%40app.cell%0Adef%20_()%3A%0A%20%20%20%20import%20numpy%20as%20np%0A%20%20%20%20import%20matplotlib.pyplot%20as%20plt%0A%0A%20%20%20%20n_observations%20%3D%20180%0A%20%20%20%20horizon%20%3D%2018%0A%20%20%20%20context%20%3D%2072%0A%20%20%20%20origins%20%3D%20np.arange(90%2C%20n_observations%20-%20horizon%20%2B%201%2C%2018)%0A%20%20%20%20return%20context%2C%20horizon%2C%20n_observations%2C%20origins%2C%20plt%0A%0A%0A%40app.cell%0Adef%20_(context%2C%20horizon%2C%20n_observations%2C%20origins%2C%20plt)%3A%0A%20%20%20%20fig_folds%2C%20axes%20%3D%20plt.subplots(2%2C%201%2C%20figsize%3D(11%2C%206)%2C%20sharex%3DTrue)%0A%20%20%20%20for%20fold%2C%20origin%20in%20enumerate(origins)%3A%0A%20%20%20%20%20%20%20%20axes%5B0%5D.barh(fold%2C%20origin%2C%20left%3D0%2C%20color%3D%22%23173f32%22)%0A%20%20%20%20%20%20%20%20axes%5B0%5D.barh(fold%2C%20horizon%2C%20left%3Dorigin%2C%20color%3D%22%23d8ff57%22%2C%20edgecolor%3D%22%2317201c%22)%0A%20%20%20%20%20%20%20%20axes%5B1%5D.barh(fold%2C%20context%2C%20left%3Dorigin%20-%20context%2C%20color%3D%22%232b78b8%22)%0A%20%20%20%20%20%20%20%20axes%5B1%5D.barh(fold%2C%20horizon%2C%20left%3Dorigin%2C%20color%3D%22%23e18719%22)%0A%0A%20%20%20%20axes%5B0%5D.set(title%3D%22Expanding%20context%22%2C%20ylabel%3D%22fold%22)%0A%20%20%20%20axes%5B1%5D.set(title%3D%22Sliding%20context%22%2C%20xlabel%3D%22time%20index%22%2C%20ylabel%3D%22fold%22)%0A%20%20%20%20for%20backtest_axis%20in%20axes%3A%0A%20%20%20%20%20%20%20%20backtest_axis.set_xlim(0%2C%20n_observations)%0A%20%20%20%20%20%20%20%20backtest_axis.grid(axis%3D%22x%22%2C%20alpha%3D0.2)%0A%20%20%20%20fig_folds.tight_layout()%0A%0A%20%20%20%20split_table%20%3D%20%5B%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%22origin%22%3A%20int(origin)%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22sliding_context%22%3A%20(int(origin%20-%20context)%2C%20int(origin%20-%201))%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%22test%22%3A%20(int(origin)%2C%20int(origin%20%2B%20horizon%20-%201))%2C%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20for%20origin%20in%20origins%0A%20%20%20%20%5D%0A%20%20%20%20return%20(split_table%2C)%0A%0A%0A%40app.cell(hide_code%3DTrue)%0Adef%20_(mo%2C%20split_table)%3A%0A%20%20%20%20first%20%3D%20split_table%5B0%5D%0A%20%20%20%20last%20%3D%20split_table%5B-1%5D%0A%20%20%20%20mo.md(f%22%22%22%0A%20%20%20%20%23%23%20Reading%20the%20folds%0A%0A%20%20%20%20The%20first%20sliding%20fold%20uses%20context%20**%7Bfirst%5B'sliding_context'%5D%7D**%20and%20test%20window%20**%7Bfirst%5B'test'%5D%7D**.%20The%20last%20uses%20context%20**%7Blast%5B'sliding_context'%5D%7D**%20and%20test%20window%20**%7Blast%5B'test'%5D%7D**.%20No%20test%20index%20appears%20inside%20its%20own%20context.%0A%0A%20%20%20%20Aggregate%20metrics%20across%20origins%20and%20inspect%20their%20spread.%20A%20model%20that%20wins%20on%20average%20but%20fails%20badly%20in%20one%20regime%20may%20still%20be%20unsafe%20to%20deploy.%0A%0A%20%20%20%20%23%23%20Practical%20takeaway%0A%0A%20%20%20%20Choose%20forecast%20origins%20that%20reproduce%20the%20real%20decision%20schedule.%20Fit%20every%20learned%20transformation%20on%20the%20past%2C%20compare%20all%20models%20on%20identical%20origins%2C%20and%20keep%20fold-level%20results%20rather%20than%20reporting%20only%20one%20average.%0A%0A%20%20%20%20%23%23%20Continue%0A%0A%20%20%20%20Next%3A%20%5BProbabilistic%20Forecasting%5D(%2Fconcepts%2Fprobabilistic_forecasting).%0A%20%20%20%20%22%22%22)%0A%20%20%20%20return%0A%0A%0Aif%20__name__%20%3D%3D%20%22__main__%22%3A%0A%20%20%20%20app.run()%0A
b5ca0ce7a0e6bf6b1d0d011f4a43fbfe