Algorithmic trading in Python
Algorithmic trading means encoding a trading decision as rules a computer can execute. Python is the default language for the research half of that work, turning an idea into signals, backtesting it honestly, and stress-testing it before any capital is at risk. This guide maps the workflow and the tools.
The research workflow
Systematic research follows a loop: form a hypothesis, express it as indicators and signals, backtest it with realistic costs, then attack the result. Most ideas die at the backtest, which is the point. The survivors get swept across parameters, validated out-of-sample with walk-forward analysis, and pressure-tested with Monte Carlo before they are ever considered for live trading.
The bottleneck is iteration speed. The faster a backtest runs, the more hypotheses you can reject per day, which is why Manifold-BT puts a Rust core under a Python API: years of bars backtest in well under a second.
The Python toolbox
A typical stack pairs pandas and numpy for data work, matplotlib or plotly for charts, and a dedicated backtesting engine for the simulation itself. Pure-Python engines are flexible but slow on large sweeps; vectorised ones are fast but awkward for path-dependent logic like stops and partial fills. Manifold-BT keeps the Python ergonomics and pushes the heavy loop into Rust, so you get both.
From one backtest to a parameter sweep
A single backtest tells you almost nothing, one set of parameters could be luck. The real test is whether a strategy works across a range of settings. Wrap your periods in mbt.param() and the engine sweeps the whole grid in parallel, ranking results by any metric:
import manifoldbt as mbt
from manifoldbt.indicators import close, ema
from manifoldbt.helpers import time_range, Slippage, Interval
# Parameters become sweepable simply by wrapping the periods
fast_p = mbt.param("fast", default=20)
slow_p = mbt.param("slow", default=50)
fast, slow = ema(close, fast_p), ema(close, slow_p)
strategy = (
mbt.Strategy.create("ema_sweep")
.signal("fast", fast)
.signal("slow", slow)
.size(mbt.when(fast > slow, 1.0, 0.0))
)
start, end = time_range("2021-01-01", "2026-01-01")
config = mbt.BacktestConfig(
universe={"binance": ["BTCUSDT"]},
time_range_start=start,
time_range_end=end,
bar_interval=Interval.hours(1),
initial_capital=10_000,
fees=mbt.FeeConfig.binance_perps(),
slippage=Slippage.fixed_bps(2),
warmup_bars=200,
)
store = mbt.ingest(provider="binance", symbol="BTCUSDT", symbol_id=1,
interval="1h", start="2021-01-01T00:00:00Z",
end="2026-01-01T00:00:00Z")
# Rank every (fast, slow) combination by Sharpe, in parallel on Rust
sweep = mbt.run_sweep(
strategy,
param_grid={"fast": [10, 20, 30], "slow": [50, 100, 150]},
config=config,
store=store,
)
print(sweep.best("sharpe"))
df = sweep.to_df()Strategies to study
The best way to learn is to read and run real strategies. Each of these walkthroughs includes the logic, runnable Python, and a sample tearsheet:
Keep reading
Run your first backtest
Install Manifold-BT and reproduce the backtest above in seconds. The Rust core runs years of bars sub-second so you can sweep parameters instead of waiting.