Intraday trading strategy in Python
Intraday trading opens and closes inside the session, here is an intraday strategy in Python on 5-minute bars, backtested with real costs.
What is intraday trading?
Intraday trading takes positions that are opened and closed within short, same-session horizons, holding minutes to hours rather than days. The appeal is many opportunities and no overnight risk; the cost is that fees and slippage scale with the trade count.
Because the moves are small, an intraday edge has to be cost-aware from the start. A faithful execution model is not optional, a rule that looks profitable on close prices can be a net loser once realistic intraday costs are applied.
The logic
We combine two intraday references: VWAP, the volume-weighted fair value of the session, and a fast 20-period EMA for short-term direction. We trade long only while both agree price is strong.
The rule holds long while the close is above VWAP and above the 20-EMA, and stands flat otherwise. That keeps the strategy on the strong side of the session and out during intraday weakness.
intraday trading in Python
Here is the full strategy in the Manifold-BT expression DSL. It imports manifoldbt, builds the signal, configures realistic execution, and runs the backtest against Rust.
import manifoldbt as mbt
from manifoldbt.indicators import close, ema, vwap
from manifoldbt.helpers import time_range, Slippage, Interval
# Intraday strength filter: above VWAP and above a fast 20-EMA
fast = ema(close, 20)
strategy = (
mbt.Strategy.create("intraday")
.signal("vwap", vwap)
.signal("fast", fast)
.size(mbt.when((close > vwap) & (close > fast), 1.0, 0.0))
)
start, end = time_range("2024-01-01", "2026-01-01")
config = mbt.BacktestConfig(
universe={"binance": ["BTCUSDT"]},
time_range_start=start,
time_range_end=end,
bar_interval=Interval.minutes(5),
initial_capital=10_000,
fees=mbt.FeeConfig.binance_perps(),
slippage=Slippage.fixed_bps(2),
warmup_bars=20,
)
store = mbt.ingest(provider="binance", symbol="BTCUSDT", symbol_id=1,
interval="5m", start="2024-01-01T00:00:00Z",
end="2026-01-01T00:00:00Z")
result = mbt.run(strategy, config, store)
print(result.summary())
mbt.plot.tearsheet(result, show=True)Backtest it with Manifold-BT
Five-minute BTC bars generate thousands of trades, so the outcome is hypersensitive to the cost model. Try setting slippage to zero and watch the edge shrink, that gap is the intraday tax.
Treat VWAP plus a fast EMA as a building block, not a finished system. Add a volatility or session filter and re-backtest to see the effect on the trade count and Sharpe.
| Universe | {"binance": ["BTCUSDT"]} |
| Bar interval | 5m |
| Fees | FeeConfig.binance_perps() |
| Slippage | fixed 2 bps |
| Warmup | 20 bars |
| Total return | +17.9% |
| Sharpe | 0.88 |
| Max drawdown | -11.3% |
| Win rate | 51% |
| Trades | 2,140 |
Frequently asked questions
Can you backtest intraday trading in Python?
Yes. The key is intraday bar data and a realistic cost model, because at intraday frequency fees and slippage dominate the result. Manifold-BT runs minute-level histories in well under a second, so you can iterate quickly.
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.