Framework for quantitative trading. Complete framework for development, backtesting, and deploying automated trading algorithms and trading bots.
See the codeBuild strategies, backtest at scale, compare results, and deploy the winner without rewriting your strategy.
Investing Algorithm Framework is a Python framework for the complete quantitative trading workflow. Define a strategy once, explore it with vector backtests, validate it in an event-driven simulation, inspect the results in an interactive dashboard, and run the same strategy in paper or live trading.
v9.0.0 alpha is available. Install the prerelease explicitly:
pip install investing-algorithm-framework==9.0.0a22See the v9.0 release notes and changelog. The APIs below describe current v9 development.
.obtf bundles.Strategies are TradingStrategy subclasses that declare their data, schedule,
signal logic, and risk rules. The framework handles data loading, order execution,
position management, persistence, and reporting around them.
from pyindicators import crossover, crossunder, ema, rsi
from investing_algorithm_framework import ConfluenceCard, CooldownRule, \
DataSource, DataType, EvidenceGroup, ExposureRule, Operator, \
PrimaryGroup, ScalingRule, Schedule, ScoreRule, SignalSide, \
StopLossRule, TakeProfitRule, TimeUnit, TradingStrategy, \
condition, PositionSize
def create_confluence_card(name, rsi_operator, rsi_value, cross_column):
return ConfluenceCard(
name=name,
primary=PrimaryGroup(name="RSI reversal", rules=(ScoreRule(
name=f"RSI {rsi_operator.value} {rsi_value}",
expression=condition("rsi", rsi_operator, value=rsi_value), points=3,
),), minimum_matches=1),
secondary=(EvidenceGroup(name="EMA confirmation", rules=(ScoreRule(
name="Recent EMA cross",
expression=condition(cross_column, Operator.GT, value=0), points=2,
),), minimum_score=2),),
minimum_score=5,
)
class RSIEMACrossoverStrategy(TradingStrategy):
schedule = Schedule.every(2, TimeUnit.HOUR)
symbols = ["BTC"]
data_sources = [DataSource(
identifier="BTC_ohlcv", symbol="BTC/EUR", data_type=DataType.OHLCV,
time_frame="2h", market="BITVAVO", pandas=True, warmup_window=100,
)]
# Portfolio and position risk controls.
exposure_rule = ExposureRule(max_portfolio_percentage=80)
position_sizes = [PositionSize(symbol="BTC", percentage_of_portfolio=20)]
scaling_rules = [ScalingRule(
symbol="BTC", max_entries=3, scale_in_percentage=[50, 25],
cooldown_in_bars=5,
)]
stop_losses = [StopLossRule(
symbol="BTC", percentage_threshold=5, sell_percentage=100, trailing=True,
)]
take_profits = [TakeProfitRule(
symbol="BTC", percentage_threshold=10, sell_percentage=50,
)]
cooldowns = [
CooldownRule(symbol="BTC", trigger="sell", blocks="buy", bars=12),
CooldownRule(trigger="any", blocks="any", bars=2),
]
# Weighted, explainable entry and exit decisions.
signal_cards = {
SignalSide.OPEN_LONG: create_confluence_card(
"Open long", Operator.LT, 30, "recent_crossover"),
SignalSide.CLOSE_LONG: create_confluence_card(
"Close long", Operator.GTE, 70, "recent_crossunder"),
SignalSide.OPEN_SHORT: create_confluence_card(
"Open short", Operator.GTE, 70, "recent_crossunder"),
SignalSide.CLOSE_SHORT: create_confluence_card(
"Close short", Operator.LT, 30, "recent_crossover"),
}
def prepare_signal_data(self, data):
"""Prepare the same card inputs for every execution mode."""
frame = data["BTC_ohlcv"].copy()
frame = ema(frame, "Close", 12, "ema_short")
frame = ema(frame, "Close", 26, "ema_long")
frame = crossover(frame, "ema_short", "ema_long", "ema_crossover")
frame = crossunder(frame, "ema_short", "ema_long", "ema_crossunder")
frame = rsi(frame, "Close", 14, "rsi")
frame["recent_crossover"] = frame["ema_crossover"].rolling(10).max()
frame["recent_crossunder"] = frame["ema_crossunder"].rolling(10).max()
return {"BTC": frame}
The framework evaluates signal_cards against the prepared columns and creates
signals and decision traces automatically. prepare_signal_data is shared by
vector backtests, event-driven backtests, paper trading, and live trading, while
the declarative rules govern sizing, exposure, scaling, exits, and cooldowns in
each mode. The four cards cover long entry and exit plus short entry and cover.
Fees and slippage belong to the portfolio or backtest study because they describe a venue or scenario rather than signal logic.
See the strategy guide, the basic example, and the strategy showcase.
Backtests use a Study to describe the experiment and a
BacktestRunConfiguration to control execution and persistence.
from investing_algorithm_framework import BacktestRunConfiguration
results = app.run_backtests(
strategies=strategies,
study=training_study,
run_configuration=BacktestRunConfiguration(
backtest_storage_directory="./my-backtests",
n_workers=8,
memory_budget_mb=16_384,
min_available_memory_mb=4_096,
),
)
print(results.df)
Both engines return a disk-backed BacktestIndex. Use the index for scalar
filtering and ranking, then load selected full results with
results.iter_backtests() or results.load_backtests().
The Polars-powered vector engine evaluates signal series in bulk. Use it for rapid signal research, parameter sweeps, large candidate sets, and early-stage filtering before running more expensive simulations.
The event engine processes market data bar by bar through the same strategy and order path used in live trading. Use it to validate execution behavior, fills, costs, portfolio changes, and interactions between strategies.
Study, Universe, and BacktestWindow support single-window tests, rolling
windows, anchored windows, holdouts, walk-forward k-fold validation, and
out-of-sample testing across time periods or universes. Execution assumptions
are captured with each study so results remain reproducible.
See the vector backtesting guide, the event backtesting guide, and the tutorial notebooks.
Each algorithm is stored as a versioned .obtf bundle using the
Open Backtest Format.
A bundle can contain studies, universes, windows, vector and event runs,
summaries, metrics, trades, orders, positions, snapshots, execution assumptions,
and Monte Carlo results.
The storage layer scales from local research to large result collections:
| Tier | Purpose |
|---|---|
| SQLite index | Rank and filter scalar metrics across 10,000+ results without decoding bundles |
BacktestStore | Swap flat LocalDirStore and partitioned LocalTieredStore layouts |
| OHLCV chunks | Deduplicate content-addressed market data shared by multiple bundles |
iaf index ./my-backtests/
iaf rank ./my-backtests/ --by sharpe_ratio \
--where "summary_number_of_trades > 50" -n 20
iaf list ./my-backtests/ --sort calmar_ratio --json
iaf migrate-store --from local-dir --src ./my-backtests/ \
--to local-tiered --dst ./tiered/
See the storage layer example.
The same strategy can run locally, in a container, as a web service, or in a serverless function. Portfolio state, orders, trades, and positions can persist across runs.
Connect to supported exchanges through CCXT or implement an OrderExecutor for
a broker, FIX gateway, or custom venue. Live mode evaluates schedules, loads
market data, creates orders, and maintains portfolio state continuously.
Paper trading exercises the live strategy path without sending real orders. Use it after event-driven validation to verify schedules, data feeds, credentials, and operational behavior in current market conditions.
Run the application on your own machine or infrastructure, package it in Docker, or scaffold AWS Lambda and Azure Functions projects from the CLI:
pip install investing-algorithm-framework
investing-algorithm-framework init
investing-algorithm-framework init --type aws_lambda
investing-algorithm-framework init --type azure_function
Publish validated strategies to the Finterion marketplace so investors can subscribe to them. The Finterion plugin handles the framework integration.
See the deployment guide and Finterion plugin.
app.add_market() configures a portfolio and its market credentials together.
Set the trading currency, starting balance, fees, slippage, position mode, and
paper-trading behavior in one place:
app.add_market(
market="BITVAVO",
trading_symbol="EUR",
initial_balance=10_000,
fee_percentage=0.1,
paper_trading=True,
)
Keep secrets outside source code with market-scoped environment variables:
BITVAVO_API_KEY=<your-api-key>
BITVAVO_SECRET_KEY=<your-api-secret>
Explicit credentials from a secret manager can be registered with
MarketCredential. Deployment-level BITVAVO_OVERRIDE_* variables can enforce
credentials, paper mode, and managed balance regardless of values supplied by
the application.
Portfolio state, orders, positions, and trades persist across runs. Optional portfolio synchronization reconciles broker balances and supports recurring or one-off deposit schedules. Local paper trading requires no real credentials.
See Portfolio Configuration, Credential Management, and Portfolio Synchronization.
BacktestReport creates a self-contained interactive HTML dashboard. Compare
strategies, inspect equity and drawdown curves, review trades, analyze monthly
and yearly returns, check window coverage, and add research notes without
running a separate server.
from investing_algorithm_framework import BacktestReport
# Materialize only the selected results when working with a large index.
BacktestReport(
backtests=results.load_backtests(workers=1),
).save("backtest-report.html")
# Or reopen a directory of persisted bundles later.
BacktestReport.open(
directory_path="./my-backtests/",
workers=-1,
show_progress=True,
).save("backtest-report.html")
The built-in MCP server lets compatible AI tools query stored backtests, compare
strategies, inspect trades, and work with report notes through
investing-algorithm-framework mcp.
See the report guide and MCP server guide.
StrategyOptimizer, budget candidate evaluations, and resume saved search state.See the advanced concepts documentation and backtest optimization guide.
Portfolios use PositionMode.NETTING by default: each symbol has one net
direction, so a long and short cannot coexist. Enable PositionMode.HEDGE to
maintain independent long and short legs for the same symbol, each with its own
entry, scaling, stop-loss, take-profit, cooldown, and P&L.
from investing_algorithm_framework import PositionMode
app.add_market(
market="BITVAVO",
trading_symbol="EUR",
initial_balance=10_000,
position_mode=PositionMode.HEDGE,
)
Both backtest engines support OPEN_LONG, CLOSE_LONG, OPEN_SHORT, and
CLOSE_SHORT independently in HEDGE mode. In NETTING mode,
flip_on_opposite_signal=True can close the current direction and open the
opposite direction on the same bar.
Live HEDGE trading requires an OrderExecutor and PortfolioProvider that
explicitly support it. The built-in CCXT adapters support NETTING only, so use
custom HEDGE-capable adapters for live execution.
Pipelines compute factors across many symbols in one pass and return a tidy cross-sectional table on each strategy iteration. Use them to define a tradeable universe, rank candidates, normalize factors, and construct multi-factor or risk-neutral signals without manually looping over symbols.
from investing_algorithm_framework import AverageDollarVolume, Pipeline, Returns
class MomentumScreener(Pipeline):
dollar_volume = AverageDollarVolume(window=30)
momentum = Returns(window=30)
universe = dollar_volume.top(100)
alpha = momentum.rank(mask=universe)
class MomentumStrategy(TradingStrategy):
pipelines = [MomentumScreener]
def generate_signals(self, context, data):
candidates = data["MomentumScreener"]
leaders = candidates.sort("alpha", descending=True).head(10)
# Yield Signal objects for the selected symbols.
...
Built-in factors include returns, liquidity, moving averages, RSI, volatility, cross-sectional means, rolling beta, and neutralization. Factors compose with arithmetic, ranking, filtering, z-scoring, demeaning, winsorization, and grouped transforms.
See the Pipelines guide, event backtest integration, vector backtest integration, and live integration.
Monte Carlo permutation testing helps distinguish a strategy's observed edge from results that randomized market paths could produce by chance. The framework runs the strategy on its original OHLCV data, creates randomized permutations, reruns the same strategy on each permutation, and compares the real metrics with the resulting null distributions.
Use app.run_monte_carlo_test(...) with a strategy, a BacktestDateRange, and
the desired number of permutations. The returned BacktestMonteCarloTest
contains the real metrics, metrics from every permuted run, the original and
permuted datasets, and p-values for metrics including:
Lower p-values indicate that fewer randomized runs matched or exceeded the observed result. They are evidence about statistical significance, not proof of future profitability. Use enough permutations for the precision you need and combine the result with out-of-sample and walk-forward validation.
See the tutorial notebooks for the robustness analysis workflow.
| Integration | Purpose |
|---|---|
| PyIndicators | Technical indicators including EMA, RSI, and MACD |
| Finterion plugin | Publish and operate strategies on Finterion |
| CCXT | Exchange market data and live order execution |
| Pandas and Polars | Native tabular inputs for strategy and backtest workflows |
| Yahoo Finance, Alpha Vantage, and Polygon | Built-in market data providers |
| AWS and Azure | Optional state storage and serverless deployment integrations |
Custom data providers, order executors, storage adapters, strategies, metrics, and optimizers can be added without replacing the core workflow.
Contributions are welcome. Open an issue, choose an existing one, or submit a
pull request against the dev branch.
git clone https://github.com/coding-kitties/investing-algorithm-framework.git
cd investing-algorithm-framework
poetry install
python -m unittest discover -s tests
Do not risk money you cannot afford to lose. Backtests and paper trading cannot guarantee future performance. Validate strategy behavior, execution assumptions, stored results, and operational safeguards before trading with real funds. The project and its contributors assume no responsibility for investment results.
Thank you to everyone who has contributed code, documentation, testing, ideas, and feedback. See AUTHORS.md for the contributor list.
Finterion is a marketplace for trading bots where strategy creators can publish and monetize their work.
Overall
Maintained
Code review
Latest release
Releases this year
316 followers ยท starred Mar 2025
38 followers ยท starred Aug 2026
91 followers ยท starred Apr 2026
634 followers ยท starred Jun 2025
Framework for quantitative trading. Complete framework for development, backtesting, and deploying automated trading algorithms and trading bots.
See the codeBuild strategies, backtest at scale, compare results, and deploy the winner without rewriting your strategy.
Investing Algorithm Framework is a Python framework for the complete quantitative trading workflow. Define a strategy once, explore it with vector backtests, validate it in an event-driven simulation, inspect the results in an interactive dashboard, and run the same strategy in paper or live trading.
v9.0.0 alpha is available. Install the prerelease explicitly:
pip install investing-algorithm-framework==9.0.0a22See the v9.0 release notes and changelog. The APIs below describe current v9 development.
.obtf bundles.Strategies are TradingStrategy subclasses that declare their data, schedule,
signal logic, and risk rules. The framework handles data loading, order execution,
position management, persistence, and reporting around them.
from pyindicators import crossover, crossunder, ema, rsi
from investing_algorithm_framework import ConfluenceCard, CooldownRule, \
DataSource, DataType, EvidenceGroup, ExposureRule, Operator, \
PrimaryGroup, ScalingRule, Schedule, ScoreRule, SignalSide, \
StopLossRule, TakeProfitRule, TimeUnit, TradingStrategy, \
condition, PositionSize
def create_confluence_card(name, rsi_operator, rsi_value, cross_column):
return ConfluenceCard(
name=name,
primary=PrimaryGroup(name="RSI reversal", rules=(ScoreRule(
name=f"RSI {rsi_operator.value} {rsi_value}",
expression=condition("rsi", rsi_operator, value=rsi_value), points=3,
),), minimum_matches=1),
secondary=(EvidenceGroup(name="EMA confirmation", rules=(ScoreRule(
name="Recent EMA cross",
expression=condition(cross_column, Operator.GT, value=0), points=2,
),), minimum_score=2),),
minimum_score=5,
)
class RSIEMACrossoverStrategy(TradingStrategy):
schedule = Schedule.every(2, TimeUnit.HOUR)
symbols = ["BTC"]
data_sources = [DataSource(
identifier="BTC_ohlcv", symbol="BTC/EUR", data_type=DataType.OHLCV,
time_frame="2h", market="BITVAVO", pandas=True, warmup_window=100,
)]
# Portfolio and position risk controls.
exposure_rule = ExposureRule(max_portfolio_percentage=80)
position_sizes = [PositionSize(symbol="BTC", percentage_of_portfolio=20)]
scaling_rules = [ScalingRule(
symbol="BTC", max_entries=3, scale_in_percentage=[50, 25],
cooldown_in_bars=5,
)]
stop_losses = [StopLossRule(
symbol="BTC", percentage_threshold=5, sell_percentage=100, trailing=True,
)]
take_profits = [TakeProfitRule(
symbol="BTC", percentage_threshold=10, sell_percentage=50,
)]
cooldowns = [
CooldownRule(symbol="BTC", trigger="sell", blocks="buy", bars=12),
CooldownRule(trigger="any", blocks="any", bars=2),
]
# Weighted, explainable entry and exit decisions.
signal_cards = {
SignalSide.OPEN_LONG: create_confluence_card(
"Open long", Operator.LT, 30, "recent_crossover"),
SignalSide.CLOSE_LONG: create_confluence_card(
"Close long", Operator.GTE, 70, "recent_crossunder"),
SignalSide.OPEN_SHORT: create_confluence_card(
"Open short", Operator.GTE, 70, "recent_crossunder"),
SignalSide.CLOSE_SHORT: create_confluence_card(
"Close short", Operator.LT, 30, "recent_crossover"),
}
def prepare_signal_data(self, data):
"""Prepare the same card inputs for every execution mode."""
frame = data["BTC_ohlcv"].copy()
frame = ema(frame, "Close", 12, "ema_short")
frame = ema(frame, "Close", 26, "ema_long")
frame = crossover(frame, "ema_short", "ema_long", "ema_crossover")
frame = crossunder(frame, "ema_short", "ema_long", "ema_crossunder")
frame = rsi(frame, "Close", 14, "rsi")
frame["recent_crossover"] = frame["ema_crossover"].rolling(10).max()
frame["recent_crossunder"] = frame["ema_crossunder"].rolling(10).max()
return {"BTC": frame}
The framework evaluates signal_cards against the prepared columns and creates
signals and decision traces automatically. prepare_signal_data is shared by
vector backtests, event-driven backtests, paper trading, and live trading, while
the declarative rules govern sizing, exposure, scaling, exits, and cooldowns in
each mode. The four cards cover long entry and exit plus short entry and cover.
Fees and slippage belong to the portfolio or backtest study because they describe a venue or scenario rather than signal logic.
See the strategy guide, the basic example, and the strategy showcase.
Backtests use a Study to describe the experiment and a
BacktestRunConfiguration to control execution and persistence.
from investing_algorithm_framework import BacktestRunConfiguration
results = app.run_backtests(
strategies=strategies,
study=training_study,
run_configuration=BacktestRunConfiguration(
backtest_storage_directory="./my-backtests",
n_workers=8,
memory_budget_mb=16_384,
min_available_memory_mb=4_096,
),
)
print(results.df)
Both engines return a disk-backed BacktestIndex. Use the index for scalar
filtering and ranking, then load selected full results with
results.iter_backtests() or results.load_backtests().
The Polars-powered vector engine evaluates signal series in bulk. Use it for rapid signal research, parameter sweeps, large candidate sets, and early-stage filtering before running more expensive simulations.
The event engine processes market data bar by bar through the same strategy and order path used in live trading. Use it to validate execution behavior, fills, costs, portfolio changes, and interactions between strategies.
Study, Universe, and BacktestWindow support single-window tests, rolling
windows, anchored windows, holdouts, walk-forward k-fold validation, and
out-of-sample testing across time periods or universes. Execution assumptions
are captured with each study so results remain reproducible.
See the vector backtesting guide, the event backtesting guide, and the tutorial notebooks.
Each algorithm is stored as a versioned .obtf bundle using the
Open Backtest Format.
A bundle can contain studies, universes, windows, vector and event runs,
summaries, metrics, trades, orders, positions, snapshots, execution assumptions,
and Monte Carlo results.
The storage layer scales from local research to large result collections:
| Tier | Purpose |
|---|---|
| SQLite index | Rank and filter scalar metrics across 10,000+ results without decoding bundles |
BacktestStore | Swap flat LocalDirStore and partitioned LocalTieredStore layouts |
| OHLCV chunks | Deduplicate content-addressed market data shared by multiple bundles |
iaf index ./my-backtests/
iaf rank ./my-backtests/ --by sharpe_ratio \
--where "summary_number_of_trades > 50" -n 20
iaf list ./my-backtests/ --sort calmar_ratio --json
iaf migrate-store --from local-dir --src ./my-backtests/ \
--to local-tiered --dst ./tiered/
See the storage layer example.
The same strategy can run locally, in a container, as a web service, or in a serverless function. Portfolio state, orders, trades, and positions can persist across runs.
Connect to supported exchanges through CCXT or implement an OrderExecutor for
a broker, FIX gateway, or custom venue. Live mode evaluates schedules, loads
market data, creates orders, and maintains portfolio state continuously.
Paper trading exercises the live strategy path without sending real orders. Use it after event-driven validation to verify schedules, data feeds, credentials, and operational behavior in current market conditions.
Run the application on your own machine or infrastructure, package it in Docker, or scaffold AWS Lambda and Azure Functions projects from the CLI:
pip install investing-algorithm-framework
investing-algorithm-framework init
investing-algorithm-framework init --type aws_lambda
investing-algorithm-framework init --type azure_function
Publish validated strategies to the Finterion marketplace so investors can subscribe to them. The Finterion plugin handles the framework integration.
See the deployment guide and Finterion plugin.
app.add_market() configures a portfolio and its market credentials together.
Set the trading currency, starting balance, fees, slippage, position mode, and
paper-trading behavior in one place:
app.add_market(
market="BITVAVO",
trading_symbol="EUR",
initial_balance=10_000,
fee_percentage=0.1,
paper_trading=True,
)
Keep secrets outside source code with market-scoped environment variables:
BITVAVO_API_KEY=<your-api-key>
BITVAVO_SECRET_KEY=<your-api-secret>
Explicit credentials from a secret manager can be registered with
MarketCredential. Deployment-level BITVAVO_OVERRIDE_* variables can enforce
credentials, paper mode, and managed balance regardless of values supplied by
the application.
Portfolio state, orders, positions, and trades persist across runs. Optional portfolio synchronization reconciles broker balances and supports recurring or one-off deposit schedules. Local paper trading requires no real credentials.
See Portfolio Configuration, Credential Management, and Portfolio Synchronization.
BacktestReport creates a self-contained interactive HTML dashboard. Compare
strategies, inspect equity and drawdown curves, review trades, analyze monthly
and yearly returns, check window coverage, and add research notes without
running a separate server.
from investing_algorithm_framework import BacktestReport
# Materialize only the selected results when working with a large index.
BacktestReport(
backtests=results.load_backtests(workers=1),
).save("backtest-report.html")
# Or reopen a directory of persisted bundles later.
BacktestReport.open(
directory_path="./my-backtests/",
workers=-1,
show_progress=True,
).save("backtest-report.html")
The built-in MCP server lets compatible AI tools query stored backtests, compare
strategies, inspect trades, and work with report notes through
investing-algorithm-framework mcp.
See the report guide and MCP server guide.
StrategyOptimizer, budget candidate evaluations, and resume saved search state.See the advanced concepts documentation and backtest optimization guide.
Portfolios use PositionMode.NETTING by default: each symbol has one net
direction, so a long and short cannot coexist. Enable PositionMode.HEDGE to
maintain independent long and short legs for the same symbol, each with its own
entry, scaling, stop-loss, take-profit, cooldown, and P&L.
from investing_algorithm_framework import PositionMode
app.add_market(
market="BITVAVO",
trading_symbol="EUR",
initial_balance=10_000,
position_mode=PositionMode.HEDGE,
)
Both backtest engines support OPEN_LONG, CLOSE_LONG, OPEN_SHORT, and
CLOSE_SHORT independently in HEDGE mode. In NETTING mode,
flip_on_opposite_signal=True can close the current direction and open the
opposite direction on the same bar.
Live HEDGE trading requires an OrderExecutor and PortfolioProvider that
explicitly support it. The built-in CCXT adapters support NETTING only, so use
custom HEDGE-capable adapters for live execution.
Pipelines compute factors across many symbols in one pass and return a tidy cross-sectional table on each strategy iteration. Use them to define a tradeable universe, rank candidates, normalize factors, and construct multi-factor or risk-neutral signals without manually looping over symbols.
from investing_algorithm_framework import AverageDollarVolume, Pipeline, Returns
class MomentumScreener(Pipeline):
dollar_volume = AverageDollarVolume(window=30)
momentum = Returns(window=30)
universe = dollar_volume.top(100)
alpha = momentum.rank(mask=universe)
class MomentumStrategy(TradingStrategy):
pipelines = [MomentumScreener]
def generate_signals(self, context, data):
candidates = data["MomentumScreener"]
leaders = candidates.sort("alpha", descending=True).head(10)
# Yield Signal objects for the selected symbols.
...
Built-in factors include returns, liquidity, moving averages, RSI, volatility, cross-sectional means, rolling beta, and neutralization. Factors compose with arithmetic, ranking, filtering, z-scoring, demeaning, winsorization, and grouped transforms.
See the Pipelines guide, event backtest integration, vector backtest integration, and live integration.
Monte Carlo permutation testing helps distinguish a strategy's observed edge from results that randomized market paths could produce by chance. The framework runs the strategy on its original OHLCV data, creates randomized permutations, reruns the same strategy on each permutation, and compares the real metrics with the resulting null distributions.
Use app.run_monte_carlo_test(...) with a strategy, a BacktestDateRange, and
the desired number of permutations. The returned BacktestMonteCarloTest
contains the real metrics, metrics from every permuted run, the original and
permuted datasets, and p-values for metrics including:
Lower p-values indicate that fewer randomized runs matched or exceeded the observed result. They are evidence about statistical significance, not proof of future profitability. Use enough permutations for the precision you need and combine the result with out-of-sample and walk-forward validation.
See the tutorial notebooks for the robustness analysis workflow.
| Integration | Purpose |
|---|---|
| PyIndicators | Technical indicators including EMA, RSI, and MACD |
| Finterion plugin | Publish and operate strategies on Finterion |
| CCXT | Exchange market data and live order execution |
| Pandas and Polars | Native tabular inputs for strategy and backtest workflows |
| Yahoo Finance, Alpha Vantage, and Polygon | Built-in market data providers |
| AWS and Azure | Optional state storage and serverless deployment integrations |
Custom data providers, order executors, storage adapters, strategies, metrics, and optimizers can be added without replacing the core workflow.
Contributions are welcome. Open an issue, choose an existing one, or submit a
pull request against the dev branch.
git clone https://github.com/coding-kitties/investing-algorithm-framework.git
cd investing-algorithm-framework
poetry install
python -m unittest discover -s tests
Do not risk money you cannot afford to lose. Backtests and paper trading cannot guarantee future performance. Validate strategy behavior, execution assumptions, stored results, and operational safeguards before trading with real funds. The project and its contributors assume no responsibility for investment results.
Thank you to everyone who has contributed code, documentation, testing, ideas, and feedback. See AUTHORS.md for the contributor list.
Finterion is a marketplace for trading bots where strategy creators can publish and monetize their work.
Overall
Maintained
Code review
Latest release
Releases this year
316 followers ยท starred Mar 2025
38 followers ยท starred Aug 2026
91 followers ยท starred Apr 2026
634 followers ยท starred Jun 2025