This tutorial demonstrates main capabilities of the Investing Algorithm Framework through a series of Jupyter notebooks. Each notebook focuses on a specific aspect of the framework, from data handling to advanced backtesting and analysis.
Note: This tutorial only showcases a subset of the framework's capabilities. Advanced features like cross-sectional pipelines can be explored in the advanced tutorials.
Note: This tutorial uses the Bitvavo exchange with EUR as the trading symbol. You can adapt the examples to other exchanges and symbols supported by the framework.
- Overview
- Tutorial Structure
- Prerequisites
- Getting Started
- Notebooks
- Key Framework Features
- Next Steps
The Investing Algorithm Framework is a comprehensive Python library for building, testing, and deploying algorithmic trading strategies. This tutorial showcases:
- Data Management - Download, validate, and fill missing market data
- Strategy Visualization - Visualize trading strategies
- In sample Parameter Sweeping - Test thousands of parameter combinations with ease through a grid search and vector backtesting.
- In sample Event Validation - Quick, cheap sanity check of the top 10 in-sample winners with the event-driven engine on just the first rolling window.
- Out sample Vector Backtesting - Test thousand of strategies out-of-sample with a fast vectorized backtester.
- Out sample event based Backtesting - Simulate realistic trade execution with an event-based backtester to validate top strategies from the vector backtest.
- Final analysis - Generate reports, rank strategies, and export results for further analysis.
tutorial/
├── README.md # This file
├── notebooks/ # Tutorial notebooks (start here!)
│ ├── 01_data_exploration.ipynb # Data download and validation
│ ├── 02_strategy_visualization.ipynb # Strategy logic visualization
│ ├── 03_in_sample_param_sweep.ipynb # In-sample parameter optimization
│ ├── 04_in_sample_event_validation.ipynb # Quick in-sample event sanity check (top 10, first window)
│ ├── 05_out_sample_vector_backtest.ipynb # Out-of-sample vector backtesting
│ ├── 06_event_backtest.ipynb # Out-of-sample event-based backtesting
│ ├── 07_robustness_analysis.ipynb # Robustness and validation
│ └── 08_final_analysis.ipynb # Final results and reporting
├── strategies/ # Strategy implementations
│ └── supertrend_ema_confirmation/ # Example strategy (v9 signal API)
├── data/ # Downloaded market data
├── backtest_results/ # Backtest results storage
└── reports/ # Generated reports / figures
- Basic Python programming
- Understanding of financial markets and trading concepts
- Familiarity with technical indicators (EMA, RSI, MACD, etc.)
- Basic knowledge of Jupyter notebooks
- Python 3.10 or higher
- Jupyter Notebook or JupyterLab
# Install the framework
pip install investing-algorithm-framework
# Install additional dependencies
pip install plotly pyindicators-
Navigate to the tutorial directory:
cd examples/tutorial -
Start Jupyter:
jupyter notebook
-
Open the notebooks folder and start with
01_data_exploration.ipynb -
Follow the notebooks in order - each builds on the previous one
File: notebooks/01_data_exploration.ipynb
Learn how to download and manage market data:
download_v2()- Download OHLCV data with path trackingget_missing_timeseries_data_entries()- Detect gaps in datafill_missing_timeseries_data()- Fill missing data pointsDownloadResult- Access both data and file path
from investing_algorithm_framework import download_v2
result = download_v2(
symbol="BTC/EUR",
market="BITVAVO",
time_frame="2h",
start_date=start_date,
end_date=end_date,
save=True,
storage_path="./data"
)
print(result.data) # DataFrame
print(result.path) # File path where data was savedFile: notebooks/02_strategy_visualization.ipynb
Visualize and understand strategy logic:
- Plot indicators (EMA, RSI) on price charts
- Visualize buy/sell signals
- Understand strategy parameters
- Interactive Plotly charts
File: notebooks/03_in_sample_param_sweep.ipynb
Define a grid of strategy variants and screen all of them with the fast vectorized engine over rolling walk-forward windows:
Study- Bundles the universe, rollingbacktest_windows, and engine choice (engines=[BacktestEngine.VECTOR])generate_rolling_backtest_windows()- Train/test rolling windows with a gap between themapp.run_backtest(strategies=..., study=...)- Batch vector backtest across the whole grid, withwindow_filter_functionprogressively pruning weak variantsbuild_index()/rank_index()- Rank thousands of on-disk bundles in milliseconds via the Tier-1 SQLite indexpromote_backtests()- Copy just the top-N winners into a dedicatedtop_selection/folder for the next notebooks
from datetime import datetime, timezone
from investing_algorithm_framework import (
generate_rolling_backtest_windows, Study, Universe, BacktestEngine,
WindowPart, StudySampleType,
)
rolling_windows = generate_rolling_backtest_windows(
start_date=datetime(2022, 1, 1, tzinfo=timezone.utc),
end_date=datetime(2025, 12, 30, tzinfo=timezone.utc),
train_days=365, test_days=180, gap_days=30, step_days=90,
)
in_sample_study = Study(
name="in_sample_param_sweep",
sample_type=StudySampleType.IN_SAMPLE,
universe=Universe(symbols=["BTC", "ETH", "ADA", "SOL", "DOT"], trading_symbol="EUR", market="BITVAVO"),
backtest_windows=rolling_windows,
window_part=WindowPart.TEST,
engines=[BacktestEngine.VECTOR],
)
backtests = app.run_backtest(
strategies=strategies,
study=in_sample_study,
backtest_storage_directory=backtest_results_dir,
show_progress=True,
)File: notebooks/04_in_sample_event_validation.ipynb
Before spending the (slower) out-of-sample vector budget on the whole top_selection/ folder, replay just the top 10 in-sample winners with the event-driven engine on only the first rolling window — a cheap sanity check that the vector engine's numbers roughly hold up once orders are routed bar-by-bar. This is also the showcase for the newest study-reuse convenience API:
get_backtests(storage_dir, algorithm_ids)/get_backtest(storage_dir, algorithm_id)- Reload specific saved bundles by id, no need to rank/open the whole directory againBacktest.get_study_definition(name)- Pull a study straight off a loaded bundle (universe, windows, execution assumptions carried over,engine_resultsreset) instead of re-declaring it by hand- Slice
study.backtest_windowsdown to the windows you actually want to (re-)run, and swapstudy.engines app.run_backtest(..., backtest_storage_directory=<same dir>)merges the new engine's results into the same<algorithm_id>.obtfbundle automatically
from investing_algorithm_framework import BacktestEngine, get_backtest, get_backtests
top_10_backtests = get_backtests(str(top_selection_path), top_10_ids)
reference_backtest = get_backtest(str(top_selection_path), top_10_ids[0])
event_study = reference_backtest.get_study_definition("in_sample_param_sweep")
# Only the first window, only the event engine.
event_study.backtest_windows = event_study.backtest_windows[:1]
event_study.engines = [BacktestEngine.EVENT_DRIVEN]
backtests = app.run_backtest(
strategies=top_10_strategies,
study=event_study,
backtest_storage_directory=str(top_selection_path),
)File: notebooks/05_out_sample_vector_backtest.ipynb
Re-instantiate the in-sample winners on two out-of-sample regimes — a different time window (Type A) and a disjoint symbol universe (Type B) — still with the fast vector engine:
Studyper regime, each with its ownsample_type(OUT_SAMPLE_TIME/OUT_SAMPLE_UNIVERSE) andUniverse- Bundles saved to the same
top_selection/folder as notebook 03, so each regime's results land as an extra study slot on the existing<algorithm_id>.obtfbundle
File: notebooks/06_event_backtest.ipynb
Full event-driven replay of both out-of-sample regimes (every rolling window, not just the first), scoped to whichever winners still look robust:
rank_by_cross_study_robustness()- Scores how much of the in-sample edge each bundle retained out-of-sample, so the (slow) event engine only runs on the most credible survivorsBacktest.get_study_definition(name)for both OOS studies,engines=[BacktestEngine.EVENT_DRIVEN]show_backtest_summaries()/show_backtest_runs()side by side forengine="vector"vsengine="event"
File: notebooks/07_robustness_analysis.ipynb
Cross-study robustness scoring and window-stability analysis across everything produced so far.
File: notebooks/08_final_analysis.ipynb
Generate final reports and analysis:
create_markdown_table()- Format results as markdownBacktestReport- Interactive HTML reports- Export results for further analysis
- Compare top strategies
from investing_algorithm_framework import create_markdown_table
# Create summary table
table = create_markdown_table(
backtests,
sort_by="sharpe_ratio",
top_n=10
)
print(table)Strategies declare what to do; the framework handles how much
and how. The example SupertrendEmaConfirmationStrategy implements
both signal methods so it works in either backtest mode:
| Method | Used by | Returns |
|---|---|---|
generate_signals(context, data) |
event backtest / live | one or more Signal(symbol, side, ...) for the latest bar |
generate_signal_series(data) |
vector backtest | one SignalSeries per (symbol, side) covering the whole window |
Sizing lives on the class as a list of PositionSize rules
(percentage_of_portfolio=... or fixed_amount=...). Risk attachments
(StopLossRule, TakeProfitRule, ScalingRule, CooldownRule) attach
to orders automatically. See docs/architecture/strategy.md for the
full contract.
| Function | Description |
|---|---|
download() |
Download market data |
download_v2() |
Download with path tracking |
fill_missing_timeseries_data() |
Fill gaps in time series |
get_missing_timeseries_data_entries() |
Detect missing data |
| Function | Description |
|---|---|
run_backtest() |
Single strategy backtest (vector or event engine, via Study.engines) |
run_backtests() |
Batch backtest across many strategies (vector or event engine, via Study.engines) |
| Function | Description |
|---|---|
rank_results() |
Rank backtests by metrics |
create_weights() |
Custom ranking weights |
BacktestEvaluationFocus |
Predefined ranking focuses |
create_markdown_table() |
Format results as markdown |
| Feature | Description |
|---|---|
backtest_storage_directory |
Persist results to disk |
use_checkpoints |
Save/resume experiments |
load_backtests_from_directory() |
Load saved backtests |
| Feature | Description |
|---|---|
n_workers |
Number of parallel workers |
batch_size |
Strategies per batch |
After completing this tutorial:
- Create your own strategy using the example as a template
- Test on different markets and time periods
- Deploy to paper trading to validate in real-time
- Go live with the framework's production capabilities
- Documentation: See
docusaurus/docs/for full documentation - Example Strategies: See
examples/strategies_showcase/ - Advanced Topics:
docusaurus/docs/Advanced Concepts/vector-backtesting.mddocusaurus/docs/Advanced Concepts/PARALLEL_PROCESSING_GUIDE.md
- Check the main framework documentation
- Review example strategies in
examples/ - Open an issue on GitHub
Happy Trading! 🚀📈
Remember: Past performance does not guarantee future results. Always test thoroughly and use proper risk management.