edgekit

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.

These are demonstrations, not signals
The bundled strategies exist to exercise the engine and the gauntlet — they are illustrative, not tuned edges (unfiltered, they are typically net-negative after costs). The workflow is always: implement a candidate, then put it through the gauntlet. Most candidates should be rejected (see the ORB example).

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 i

The 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
ParamTypeDefaultMeaning
barspd.DataFrameOHLC frame (tz-naive UTC DatetimeIndex, float open/high/low/close).
costCostModel | NoneNoneCost model; default = the library convention (12 bps round-trip + 2 bps/day).
warmupint210Bars to skip before trading (indicator warmup).
bars_per_dayfloat6.0Converts 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)
ParamDefaultMeaning
or_bars30Bars in the opening range (its width = 1R).
target_r2.0Flatten 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)
!Session-slice first
The session is derived from the bar index's calendar day — pre-slice / localise the frame to your trading session before backtesting. Being intraday, pass a small 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)
ParamDefaultMeaning
fast20Fast SMA period.
slow100Slow SMA period.
atr_n20ATR period for the stop distance.
stop_mult2.0Hard 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#