edgekit.strategy
Small, illustrative strategy templates expressed against the causal Strategy interface. Each subclasses BaseStrategy: prepare builds lagged indicator arrays, entry/exit make per-bar decisions, and .backtest(bars) runs the R-multiple bar loop. Bring your own strategy by subclassing the base.
What's inside. The abstract base BaseStrategy, plus two concrete templates: ORB (an intraday opening-range breakout) and SmaCross (a fast/slow moving-average crossover). Both are plain textbook demos built on the same interface.
BaseStrategy (ABC)#
The abstract base implementing the engine's Strategy protocol. Subclasses set a name and implement three methods; they inherit the one-line backtest wiring.
prepare(self, bars) -> dict # precompute causal indicator arrays (the P dict)
entry(self, bars, P, i) -> EntryIntent | None # entry decision on a flat bar i
exit(self, bars, P, pos, i) -> float | None # exit price on an in-position bar iThe inherited convenience method runs the strategy through run_bar_loop and returns the canonical trade DataFrame priced in R:
backtest(self, bars, cost: CostModel | None = None, warmup: int = 210,
bars_per_day: float = 6.0) -> pd.DataFrame| Param | Type | Default | Meaning |
|---|---|---|---|
bars | pd.DataFrame | — | OHLC frame (tz-naive UTC DatetimeIndex, float open/high/low/close). |
cost | CostModel | None | None | Cost model; default = the library convention (12 bps round-trip + 2 bps/day). |
warmup | int | 210 | Bars to skip before trading (indicator warmup). |
bars_per_day | float | 6.0 | Converts hold-in-bars to days for the swap cost (H4 = 6/day). |
Returns the canonical trade frame: one row per closed trade with net R in r, exit date in date, plus dir, bars_held, entry, exit, stop_dist, tag, exit_reason.
ORB#
Opening-range breakout — a classic intraday breakout, as a plain template.
ORB(or_bars: int = 30, target_r: float = 2.0)| Param | Default | Meaning |
|---|---|---|
or_bars | 30 | Bars in the opening range (its width = 1R). |
target_r | 2.0 | Flatten at target_r × risk (or at end of session). |
Each session's first or_bars bars define an opening range; a break of its high goes long / its low goes short, with the stop at the opposite edge (range width = 1R). One trade per day, flattened at the session end.
import edgekit as ek
from edgekit.strategy import ORB
rth = bars[ek.data.rth_mask(bars.index, start="09:30", end="16:00", tz="America/New_York")]
trades = ORB(or_bars=30, target_r=2.0).backtest(rth, warmup=5, bars_per_day=390)warmup and a bars_per_day matching your bar size. This is the raw, unfiltered breakout skeleton — a demonstration, not a tuned edge.SmaCross#
A vanilla fast/slow moving-average crossover with an ATR stop — the textbook trend-following template.
SmaCross(fast: int = 20, slow: int = 100, atr_n: int = 20, stop_mult: float = 2.0)| Param | Default | Meaning |
|---|---|---|
fast | 20 | Fast SMA period. |
slow | 100 | Slow SMA period. |
atr_n | 20 | ATR period for the stop distance. |
stop_mult | 2.0 | Hard stop distance in ATRs (the R denominator). |
Go long when the fast SMA crosses above the slow SMA, short on the opposite cross; exit on a stop_mult×ATR stop or when the SMAs cross back. All indicators are lagged, so bar i only sees information through i-1.
from edgekit.strategy import SmaCross
trades = SmaCross(fast=20, slow=100).backtest(bars, warmup=210, bars_per_day=6)Writing your own#
Subclass BaseStrategy, precompute (and lag) your indicators in prepare, return an EntryIntent(direction, level, stop_dist) from entry, and an exit price from exit. The engine handles gap-aware fills, the R accounting, and costs. See the custom-strategy guide and the tutorial chapter for a full walkthrough.
See also#
- edgekit.engine — the bar loop and the
Strategyprotocol. - edgekit.validation — prove a strategy before you trust it.
- edgekit.portfolio — combine several strategies into one book.