edgekit

A taxonomy of strategies

There are only a handful of genuinely distinct ways to make money in markets, and each one is a bet on a specific recurring behaviour: that trends persist, that ranges hold, that cheap risk pays a premium, that a temporary imbalance will correct. This chapter is a field guide to the archetypes — for each, the mechanism, the market behaviour it exploits, when it works and when it dies, a one-line signal sketch, and whether edgekit ships a template you can start from.

These are the general archetypes, not proprietary edges
Everything below is textbook strategy taxonomy — the public vocabulary of the field. edgekit ships two concrete research templates you can run and read: SmaCross (a trend-following crossover) and ORB (an opening-range breakout). The other families are described conceptually; some you would assemble from the indicator primitives. None of them is presented as a working edge — an archetype is a hypothesis, and the gauntlet decides whether any given instance is real.

The families at a glance#

FamilyTypical horizonWhat it exploitsMain riskedgekit template
Trend-followingDays–monthsPersistence / autocorrelation of returnsWhipsaw in ranges; long flat stretchesSmaCross
BreakoutIntraday–daysRange expansion / volatility clusteringFalse breaks; chopORB
Momentum (cross-sectional)Weeks–monthsWinners keep winning vs peersCrashes / sharp reversalsconceptual
Momentum (time-series)Weeks–monthsAn asset's own trend signRegime flips; beta in disguiseconceptual
Mean-reversionMinutes–daysOverreaction reverting to a meanTrends that don't revert (fat left tail)conceptual
Statistical arbitrage / pairsHours–daysA stable relationship between assetsRelationship breaking (de-cointegration)conceptual
CarryWeeks–monthsA premium for holding a positionRare, violent unwindsconceptual
Market-makingSub-second–minutesThe bid-ask spread; liquidity provisionAdverse selection; inventoryout of scope
Event-drivenEvent-scopedPredictable reaction to scheduled newsGaps; slippage; surprise directionconceptual
ML-basedAnyWeak patterns across many featuresOverfitting; leakagePart V

Trend-following#

Mechanism. Buy what is going up, sell what is going down, and hold until the trend gives way. Entries key off a moving-average relationship or a channel; exits are trailing, so winners run and losers are cut quickly. What it exploits: positive autocorrelation of returns — the empirical tendency for large moves to extend as capital, information, and herding push in one direction over weeks to months.

Signal sketch: (or when price breaks the -bar high). Works in strong, sustained directional regimes and across many uncorrelated markets at once (diversification smooths the flat spells). Fails in choppy, range-bound markets, where the crossover flips repeatedly and every entry is a small loss; the return profile is a low win rate rescued by a fat right tail, so it demands patience through long drawdowns. edgekit ships SmaCross.

from edgekit.strategy import SmaCross
trades = SmaCross(fast=20, slow=100, atr_n=20, stop_mult=2.0).backtest(h4, warmup=210, bars_per_day=6)

Scenario (what it feels like to trade). On BTCUSDT H4 the fast MA crosses up through the slow at 64,900 and you go long with a 2-ATR stop. Price grinds to 78,000 over six weeks and the trail eventually closes you at 74,500 — a fat winner. But that one trade sat inside a run of nine entries: the other eight were small whipsaws in choppy stretches, each closing near . Net across the nine you are positive only because the single trend paid for all the paper cuts. That lopsided arithmetic — many small losers, one outsized winner — is the trend-following experience, and why you must survive the flat stretches to collect the one that matters.

Breakout#

Mechanism. Define a reference range — an opening range, a prior-day range, an -bar channel — and act when price escapes it, stop at the opposite edge. What it exploits: volatility clustering and range expansion — quiet coils tend to resolve into directional bursts, and the moment of escape often precedes the largest part of the move.

Signal sketch: , stop at the range low. Works when a real catalyst drives follow-through (news, session opens, regime shifts). Failsas the classic “false breakout”: price pokes through, triggers the crowd, and snaps back — so unfiltered breakouts are typically net-negative after costs, and the edge, if any, lives in filtering which breaks to trust. edgekit ships ORB (opening-range breakout).

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)

Scenario (a true break and a false one). US100 opens at 09:30 New York; the first 30 minutes carve a range of 40 points (18,000–18,040). That 40-point width is 1R. Monday: at 10:05 price prints 18,041, the buy-stop triggers, a fresh CPI-driven trend carries it to 18,120 and the 2R target (18,120) fills — . Tuesday: same setup, price ticks to 18,042, triggers the long, then immediately sags back inside the range and slides to 17,999 — stopped at the lower edge for . Identical mechanics, opposite outcome; the raw signal cannot tell them apart in advance, which is the whole reason the edge (if any) lives in a filter, not the break.

!The raw breakout is usually a loser
Plain ORB across a full history is typically net-negative after costs — that is the honest baseline, and exactly why it makes a good teaching example. Any edge comes from a selection layer (a volatility gate, a retest entry, a meta-label) applied on top, not from the breakout itself.

Momentum#

Momentum splits into two related but distinct constructions.

Cross-sectional momentum#

Mechanism. Rank a universe of assets by recent return; go long the top slice, short the bottom, rebalance periodically. It is a relative bet — long the strongest against the weakest — and is naturally market-neutral-ish. Exploits: the persistence of relative performance (winners keep beating losers over weeks to months). Signal sketch: . edgekit ships the cross_sectional_rank primitive for the ranking; the strategy is conceptual.

ranks = ek.indicators.cross_sectional_rank(trailing_return_matrix)   # 1.0 = strongest that date

Failsin momentum crashes — sharp reversals where yesterday's losers rip and the short book is run over. The left tail is brutal and clustered.

Time-series momentum#

Mechanism. Trade each asset on the sign of its own trailing return, independent of peers — long if it has been going up, short if down. Exploits: the same persistence, per-asset. Signal sketch: . The trap here is that long-only time-series momentum on a rising asset is often just beta — market exposure dressed as alpha — so the honest test is whether the short side also pays (see alpha vs beta). Conceptual in edgekit.

Mean-reversion#

Mechanism. Fade extremes: buy when price is stretched far below a reference, sell when stretched far above, exit as it reverts. Exploits:short-horizon overreaction — order-flow imbalances and liquidity gaps that push price away from “fair” and then correct. Signal sketch: using the rolling z-score. Works in range-bound, liquid markets (index ETFs are the classic home). Failscatastrophically in a trend — a mean-reverter's losers are open-ended because a genuinely trending price never reverts, giving it a high win rate masking a fat left tail. It is, in a precise sense, the mirror image of trend-following, which is why the two diversify each other. edgekit's shippedSmaCross is a trend template; mean-reversion is conceptual here, built from the zscore / rsi primitives.

Scenario (the fade that works, and the one that doesn't). An index ETF closes 2.5 sigma below its 60-bar mean after a liquidity-driven flush. You buy the dislocation; over the next three bars it snaps back to the mean for a clean . This happens over and over — you win maybe seven times in ten. Then a real regime change hits: price is 2.5 sigma below the mean and keeps going— 3 sigma, 4 sigma, the mean itself sliding down after it. Your stop is far away (that is how the win rate got so high), so the one loser gives back six winners in a single trade. High hit rate, fat left tail — the mean-reverter's signature and its trap.

High win rate is not high expectancy
Mean-reversion tempts beginners because it wins often. But expectancy is : a 75% win rate with tiny winners and rare huge losers can still be negative. Always judge on expectancy and profit factor, never on hit rate.

Statistical arbitrage & pairs#

Mechanism. Find two (or more) assets whose prices move together, trade the spreadbetween them rather than either outright: short the rich leg, long the cheap leg, collect the convergence. Because the market exposure cancels, it is close to market-neutral. Exploits: a stable statistical relationship — cointegration — between assets driven by the same underlying factor.

The construction has three standard ingredients, all of which edgekit provides as primitives:

  • Hedge ratio — a rolling regression of one leg on the other gives the spread you actually trade (ek.indicators.rolling_ols_hedge).
  • z-score — standardise the spread; enter when is large, exit as it returns toward zero (ek.indicators.zscore).
  • Half-life — the Ornstein-Uhlenbeck half-life of the spread measures how fast it reverts; a short half-life is a live pair, an infinite one is a coincidence (ek.indicators.half_life).
alpha, beta, spread = ek.indicators.rolling_ols_hedge(leg_y, leg_x, win=90)
z  = ek.core.lag(ek.indicators.zscore(spread, 60), 1)   # trade the spread's z-score
hl = ek.indicators.half_life(spread)                    # short half-life = a reverting pair

Scenario (trading the spread, not the leg).Two related equity indices normally move together; the rolling hedge says leg-Y ≈ 1.3 × leg-X, and the spread's z-score is +2.2 with a half-life of 6 days. You do not care which index goes up — you short the rich leg and long the cheap leg so the market exposure nets to roughly zero, and you collect the convergence as z decays toward 0. It works for weeks. Then a sector shock hits only one of the two names: the spread blows out to +5 sigma and never comes back — the relationship de-cointegrated. That open-ended divergence, not a normal loss, is how a pairs book takes its worst hit, and why cointegration that held in-sample must be re-proven out-of-sample before you trust it.

Signal sketch: .Fails when the relationship breaks — a structural change de-cointegrates the pair and the spread walks away instead of reverting, which is how pairs books suffer their worst losses. Cointegration that held in-sample routinely fails to replicate out-of-sample, so this family demands especially ruthless validation. Conceptual in edgekit.

Carry#

Mechanism. Get paid to hold a position: earn the roll/funding/interest differential and hope the spot price does not move against you enough to erase it. Exploits: a structural risk premium — someone pays to hedge, and the carry trader collects it. Examples are FX interest-rate differentials, futures term-structure roll, and perpetual-swap funding. Signal sketch: . Works in calm regimes, where the premium accrues steadily. Failsin the tail: carry returns look like picking up coins in front of a steamroller — long stretches of small gains punctuated by rare, violent unwinds (the “carry crash”). Conceptual; often needs an own-capital venue rather than a CFD account.

Market-making#

Mechanism. Quote a bid and an ask simultaneously and earn the spread when both fill, while managing inventory back toward flat. Exploits: the compensation liquidity providers receive for immediacy. Main risk:adverse selection — you get filled precisely when an informed trader knows something you don't — plus inventory risk when the market runs one way. This is a latency- and infrastructure-bound game measured in microseconds; it is out of scopefor edgekit's bar-based research engine, which assumes you cross the spread as a taker (that cost is charged in R).

Event-driven#

Mechanism. Trade around scheduled or discrete events — earnings, economic releases, index rebalances, expiries — where the reaction is more predictable than the direction. Exploits: structured, repeatable behaviour clustered in time. Signal sketch: . Works when the reaction pattern is stable and you can be positioned before the crowd. Failson the gap-and-slippage problem — the biggest moves happen in an instant with no fill in between, and a surprise flips the sign. Conceptual; edgekit's session and calendar tooling (ek.data.rth_mask, minute_of_day) is the scaffolding you would build the event clock on.

ML-based#

Mechanism.Instead of a hand-written rule on one feature, fit a model across many features and let it learn the mapping to a labelled outcome (e.g. “did this setup reach +1R before −1R?”). Exploits: weak, interacting patterns no single threshold captures — most usefully as a meta-label that filters a base strategy's signals rather than as a standalone predictor. Main risk: overfitting and leakage — with enough features and enough tuning, a model will fit noise perfectly and generalise to nothing. This is the highest-variance family: the ceiling is real, but so is the number of ways to fool yourself. Covered in Part V, built on edgekit.ml.

Choosing a family is choosing a regime bet#

Notice the through-line: trend-following and breakout profit from expansion and continuation; mean-reversion and pairs profit from contraction and convergence; carry profits from calm; event-driven from structure. No family wins in every regime — each is a bet that a particular market behaviour will recur. That is why serious books combine uncorrelated families (trend + reversion, directional + market-neutral) so the one that is suffering is offset by the one that is thriving — the subject of portfolio construction.

Strategy performance broken out by market regime
Each family is a regime bet: performance concentrates in the regime it was designed for and gives back in the others. Diversifying across families smooths the whole.

Next: Build your first strategy — take two of these templates from data load to trade statistics, end to end.