Files
manifoldbt/examples/01_trend_following.py
T

81 lines
2.5 KiB
Python
Raw Normal View History

2026-03-17 16:13:34 +01:00
"""Trend Following -- EMA crossover with stop-loss and dynamic sizing.
Demonstrates:
- Fluent Strategy builder
- EMA indicators
- Conditional sizing with when()
- Stop-loss via .stop_loss()
- Diagnostics (lookahead, exposure stability, risk)
- result.summary() rich output
2026-08-23 13:31:37 +00:00
Data: shared store — real market data from `data/` (see examples/README.md)
2026-03-17 16:13:34 +01:00
Usage:
python examples/01_trend_following.py
"""
import os
import time
import manifoldbt as mbt
from manifoldbt.indicators import ema, close, volume
from manifoldbt.helpers import time_range, Slippage, Interval
# -- Indicators ---------------------------------------------------------------
fast = ema(close, 12)
slow = ema(close, 26)
trend = fast - slow # MACD-like spread
vol_ma = volume.rolling_mean(20) # average volume filter
# -- Strategy -----------------------------------------------------------------
strategy = (
mbt.Strategy.create("trend_following")
.signal("fast", fast)
.signal("slow", slow)
.signal("trend", trend)
.signal("vol_filter", volume > vol_ma) # only trade on above-average volume
.size(mbt.when((trend > 0.0) & (volume > vol_ma), 0.5, 0.0))
.stop_loss(pct=3.0)
.describe("EMA(12/26) crossover, volume filter, 3% stop-loss")
)
# -- Config -------------------------------------------------------------------
start, end = time_range("2022-01-01", "2025-01-01")
config = mbt.BacktestConfig(
2026-04-01 01:18:05 +02:00
universe={"binance": ["BTC-USDT:perp"]},
2026-03-17 16:13:34 +01:00
time_range_start=start,
time_range_end=end,
2026-03-21 11:50:25 +00:00
bar_interval=Interval.hours(1),
2026-03-17 16:13:34 +01:00
initial_capital=10_000,
execution=mbt.ExecutionConfig(
allow_short=False,
max_position_pct=0.5,
position_sizing_mode="FractionOfInitialCapital",
),
2026-03-21 11:50:25 +00:00
output_resolution=Interval.hours(1),
2026-03-17 16:13:34 +01:00
fees=mbt.FeeConfig.binance_perps(),
slippage=Slippage.fixed_bps(2),
warmup_bars=30,
)
# -- Run ----------------------------------------------------------------------
if __name__ == "__main__":
root = os.path.join(os.path.dirname(__file__), "..")
2026-04-01 01:18:05 +02:00
data_root = os.path.abspath(os.path.join(root, "data"))
2026-03-17 16:13:34 +01:00
store = mbt.DataStore(
2026-04-01 01:18:05 +02:00
data_root=data_root,
2026-03-17 16:13:34 +01:00
metadata_db=os.path.abspath(os.path.join(root, "metadata", "metadata.sqlite")),
2026-04-01 01:18:05 +02:00
arrow_dir=os.path.join(data_root, "mega"),
2026-03-17 16:13:34 +01:00
)
# Backtest
t0 = time.perf_counter()
result = mbt.run(strategy, config, store)
elapsed = time.perf_counter() - t0
print(result.summary())
print(f"\nElapsed: {elapsed:.3f}s")
# Plot
2026-07-19 02:07:07 +00:00
mbt.plot.summary(result)