The strategy catalog — twenty-nine panel/event shapes, one ranking helper
what you'll learn · The twenty-nine strategies currently registered in alphakernel, how they share the cross-sectional ranking machinery, and how they decompose along the panel-clock × event-clock axis.
alphakernel ships seven registered live-trading strategies. Six of them share a single 17-line ranking helper, then differ only in their score function. The catalog is the working surface of the platform — what an operator can point a runner at, what an A/B harness can measure, what citation graphs read.
alphakernel registers twenty-nine strategies as of writing. Twenty-eight of them
share a single 17-line cross-sectional ranking helper
(_xs_weights_from_scores, ADR-0057) and differ only in the score
function or the per-tick gate. This note is the catalog — what’s
shipped, how the shapes relate, and where to point a runner.
The runner reads slug from a strategy’s class attributes; everything
else (cites, feature_slugs, intent) lives in the provenance
row. ak strategies list surfaces the full catalog with one
command.
Panel-clock signals
These read prices on the bar cadence; no event awareness.
| Slug | Score | Note |
|---|---|---|
equal_weight_long |
1/N per priced symbol |
Pipeline exerciser. intent="exerciser"; no thesis. |
xs_momentum_live |
log(P_t / P_{t-lookback}) |
The unit — single-factor momentum, top/bottom quantile sorted. |
xs_long_only_momentum |
top-quantile only | Long-only variant for operators who can’t short (cash accounts, IRAs, mutual-fund mandates). Default gross_leverage=1.0. |
xs_vol_weighted_momentum |
log(P_t / P_{t-lookback}) / std(returns) |
Vol-scaled momentum — risk-adjusted version of the unit. Often the top arm in real-data tests. |
xs_momentum_with_spread_filter |
XsMomentum + chop filter |
Only fires when top-bottom spread > threshold. Closes the chop hole the strategy-shape-beats-factor-count note named. |
xs_momentum_with_vol_regime_filter |
XsMomentum + per-symbol vol-regime gate |
Drops symbols whose vol_5/vol_60 exceeds threshold. Scale-invariant gate per vol-ratio-as-cross-symbol-regime-gate. Tops mean Sharpe on the harness; pays in variance per vol-regime-filter-mean-vs-variance. |
time_series_momentum |
per-symbol ` | log return |
xs_three_clock_momentum |
linear combination of mom_5, mom_20, mom_60 | Composite-horizon momentum. Default weights (-0.5, +1.0, +0.5) express short-reversion + medium-trend + long-confirm. Highest min-Sharpe across seeds; see three-clock-momentum-tops-the-harness. |
xs_three_clock_momentum_with_vol_regime |
three-clock score + vol-regime gate | Composite of the two top arms. INTERFERES on single-signal data, STACKS on dual-signal — see composite-strategies-can-interfere and dual-signal-makes-composites-stack. |
xs_mean_revert |
-log(P_t / P_{t-lookback}) over short lookback |
Sign-flipped momentum. Short-clock cross-sectional reversion. Diagnostic arm for the dual-signal harness mode (PR #681) — picks up short-clock mean-reversion when present, penalised when not. |
xs_momentum_with_vol_regime_transition_filter |
XsMomentum + per-symbol vol-CHANGE gate |
Drops symbols whose |vol_5_now / vol_5_prev - 1| exceeds threshold. Fix attempt for vol_regime_filter’s clustered-vol underperformance; disconfirmed (see disconfirmed-the-transition-gate-fix). |
xs_momentum_with_vol_penalty |
XsMomentum − vol_penalty × vol_5/vol_60 |
Score-stage continuous vol penalty. Interpretation B from PR #723 — different intervention point than the filter variants. |
xs_momentum_with_portfolio_vol_gate |
XsMomentum × portfolio_scale(median vol_5/vol_60) |
CROSS-SYMBOL vol intervention: universe-wide median vol sizes the whole portfolio down. Recovers 75-80% of the Sharpe gap per-symbol variants lose (PR #737). |
xs_three_clock_momentum_with_portfolio_vol_gate |
three-clock × portfolio_vol_gate | Composite at MIXED stages (per-symbol × cross-symbol). Interferes at +1.00 correlation with three_clock (gate dormant on this data); see perfect-correlation-explains-the-interference. |
xs_three_clock_vol_weighted_momentum |
three-clock score / per-symbol std | Composite at SAME stage (score × score) of the most-decorrelated pair (+0.71). At N=10 beat both parents; at N=100 ties baseline (see hundred-seeds-confirms-and-converges). |
xs_time_series_filtered_momentum |
ts-momentum filter + cross-sectional rank | Composite: |
xs_time_series_active_set_momentum |
ts-momentum filter + sign-preserving magnitude weighting | Composite: same filter, weights = sign × relative magnitude. Recovers the sign discipline ts_filtered broke. Recovers most of ts_momentum’s edge without stacking above it. |
xs_ranked_momentum_with_vol_threshold |
XsMomentumLive + per-symbol absolute-vol floor | Pure rank-based + absolute-vol filter (no sign conflict). Pairwise-rule prediction: behaves like baseline. Empirically confirmed at N=100: +0.830 vs baseline +0.863, within stdev. |
xs_momentum_ma_crossover |
(MA_short - MA_long) / MA_long | Different score-stage shape from raw return — smooths over per-day noise. N=100: +0.742 (below baseline +0.863) with lower stdev (1.033 vs 1.077) and better worst-case. |
xs_vol_weighted_mean_revert_composite |
momentum_weight × (mom/std) + revert_weight × (-short_clock_return) | Score-stage composite of anti-correlated parents (-0.42). Predicted to stack; empirically ties vol_weighted parent (anti-correlation hedges, doesn’t stack — see anti-correlation-hedges-not-stacks). |
xs_momentum_live_with_ma_composite |
mom_weight × log(P/P_lookback) + ma_weight × (MA_short - MA_long)/MA_long | Score-stage composite at +0.70 correlation (ADR-0062 marginal band). First robust single-signal stack: +0.071 above baseline at N=100 (see the-first-robust-single-signal-stack). Redundant-measurement composition: both parents see 20-day momentum at different smoothing scales. |
xs_vol_weighted_three_clock_composite |
vw_weight × (mom/std) + tc_weight × (multi-horizon momentum) | Same +0.70 correlation as mom_ma_composite but parents measure DIFFERENT quantities (vol-adjustment vs horizon-stacking). INTERFERES below both parents (multiplicative interference per ADR-0062’s 5th condition; see redundant-vs-multiplicative-composition). The empirical contrast that confirmed the 6th iteration. |
xs_two_factor |
mom + w_z × zscore |
Adds mean-reversion. Default w_z = -1 makes it reversion-dominant. |
xs_three_factor |
mom + w_z × zscore + w_s × skew |
Adds tail-skew aversion. Default w_s = -1 shorts positively-skewed names. |
xs_four_factor |
mom + w_z × zscore + w_s × skew + w_k × kurtosis |
Adds tail-fatness aversion. Default w_k = -0.5; see higher-moments-add-noise-faster-than-signal for tuning. |
Each non-exerciser strategy cites
walk-forward-without-leakage for
the live-cadence discipline and
the-deploy-contract-isnt-a-yaml-file
for the citation interface. All four use the same ranking helper —
the score is the only thing that changes.
Event-aware wrappers (around the panel signal)
These read panel prices but consult an event_release silver table
to gate or modulate exposure around scheduled releases.
| Slug | Shape | Window | Mode |
|---|---|---|---|
xs_momentum_with_fomc_blackout |
Binary gate, flat-inside | 24h pre-event | Risk reduction |
xs_momentum_post_fomc_drift |
Binary gate, trade-inside | 4h post-event | Alpha capture (continuation) |
xs_momentum_post_event_reversal |
Binary gate, trade-inside (sign-flipped) | 4h post-event | Alpha capture (mean-reversion) |
xs_momentum_with_event_damping |
Continuous gate | Exponential 1 − e^(−τ/half_life) around any release |
Risk reduction (smooth) |
All four wrappers accept release_kind_filter (default "fomc",
or None for any-kind, or "earnings" etc.) so a new event-kind
adapter automatically extends the wrapper coverage without class
changes.
The drift and reversal wrappers are direct counterfactuals — see
drift-vs-reversal-as-counterfactual
for the discipline rule of running both arms to measure whether
the post-event regime is continuation- or reversion-flavored.
All three cite
the-event-clock-isnt-the-panel-clock
for the surface and one or more of the discipline notes
(dont-pay-for-caution-you-cant-justify,
the-baseline-arm-you-forgot,
event-aware-needs-signal-concentration)
for the measurement bar they have to clear. The damping strategy
is release-agnostic; the blackout and drift are FOMC-only by class
(release-agnostic versions are a parameter away — the existing
filter_fn shape supports it).
Per-tick citation: each wrapper sets
cited_event_artifacts = ("event:event_release/<id>",) while
inside its gating zone, cleared outside. The ADR-0031 cooldown rule
reads that citation when deciding whether to gate.
The decomposition
Two orthogonal axes — score shape (how do we rank within the
universe?) and entry rule (when do we trade at all?). Most of
the catalog varies on the score axis; time_series_momentum and
xs_momentum_with_spread_filter are the catalog’s two entry-rule
shapes.
Score axis
| Panel-only score | Event-aware gate | |
|---|---|---|
| Long-only single-factor | xs_long_only_momentum |
(compose with any wrapper) |
| Single-factor | xs_momentum_live, xs_vol_weighted_momentum |
…_with_fomc_blackout, …_post_fomc_drift, …_post_event_reversal, …_with_event_damping |
| Multi-window single-factor | xs_three_clock_momentum |
(compose with any wrapper) |
| Mean-reversion (short-clock) | xs_mean_revert |
(compose with any wrapper) |
| Composite (score + gate) | xs_three_clock_momentum_with_vol_regime, xs_three_clock_momentum_with_portfolio_vol_gate |
(compose with any wrapper) |
| Composite (score × score) | xs_three_clock_vol_weighted_momentum, xs_time_series_active_set_momentum |
Sign-preserving same-stage composition |
| Composite (filter × rank) | xs_time_series_filtered_momentum |
Sign-vs-rank conflict; documented failure mode |
| Two-factor | xs_two_factor |
(compose with any wrapper) |
| Three-factor | xs_three_factor |
(compose with any wrapper) |
| Four-factor | xs_four_factor |
(compose with any wrapper) |
Entry-rule axis
| Entry rule | Strategy | Notes |
|---|---|---|
| Always trade quantiles | every Xs* score variant above | Default cross-sectional shape. |
| Trade only when top-bottom spread > threshold | xs_momentum_with_spread_filter |
Closes cross-sectional chop. |
| Trade only when per-symbol vol_5/vol_60 under threshold | xs_momentum_with_vol_regime_filter |
Per-symbol vol level gate. The original “clustered-vol breaks the gate” claim (vol-cluster-breaks-the-regime-filter) was small-N noise — see the-clustered-vol-finding-was-also-small-n for the N=30 re-run that disconfirms it. The gate still loses ~0.21 Sharpe to baseline on i.i.d.-vol data at N=100. |
| Trade only when per-symbol |Δvol| under threshold | xs_momentum_with_vol_regime_transition_filter |
Per-symbol vol change gate. Disconfirmed fix (PR #719). |
| Size portfolio down when universe-wide vol elevated | xs_momentum_with_portfolio_vol_gate |
CROSS-SYMBOL intervention. Best vol-aware variant. |
| Score-stage continuous vol penalty | xs_momentum_with_vol_penalty |
Per-symbol continuous; doesn’t drop symbols. |
| Trade per-symbol only when |absolute return| over threshold | time_series_momentum |
Closes time-series chop. |
The wrappers compose orthogonally with the multi-factor scores:
XsMomentumWithFomcBlackoutStrategy(inner=XsTwoFactor(...)) is a
trivial follow-up if the operator wants a two-factor signal
plus a pre-event flatten. The shipped wrappers only wrap
XsMomentumLive because that’s all that’s been needed so far —
the seam is there to widen when the question warrants it.
How an operator picks
The
designing-an-event-aware-strategy
checklist names the six steps. The short version:
- Panel-only signal works on the data? If no, fix the signal first — wrappers can’t add alpha to noise.
- Is there an event that should change exposure? If yes, the wrappers are the next move. If no, two-factor or three-factor may.
- A/B all of it. The 31-arm harness in
examples/fomc_blackout_compare.pyruns every strategy in this note against the same synthetic data in one command. Add real data when it lands.
For the cross-arm findings the harness has surfaced so far —
including the stack-vs-interfere result for composites and the
mean-vs-variance trade for the regime gate — see
what-24-arms-told-us. It’s the
session-summary index over the per-strategy notes.
Synthetic-equivalence note (real data may differ)
At N=100 seeds on the default single-signal synthetic, several
catalog entries are statistically indistinguishable
(see hundred-seeds-confirms-and-converges):
| Equivalence class | Arms | Reason |
|---|---|---|
baseline ≈ xs_momentum_with_spread_filter |
both at +0.863 | chop filter rarely fires on this synthetic |
xs_three_clock_momentum ≈ xs_three_clock_momentum_with_portfolio_vol_gate ≈ xs_three_clock_vol_weighted_momentum |
all at +0.798 | universe vol rarely crosses threshold; vol-weighting marginal |
The arms are NOT identical — they intervene at different stages (score, portfolio scale, score-normalisation). On REAL data with active vol regimes and cross-symbol correlation structure, the variants should diverge. This catalog keeps all of them because:
-
Synthetic-equivalence is data-specific. A future alphakernel run on Polygon bars might find the chop filter firing 15% of the time (where the synthetic has it firing 0%), separating
spread_filterfrombaseline. -
Deprecating a shipped strategy sends a stale-thesis signal per ADR-0014. The strategy doesn’t claim to work; the catalog claims to have it available.
-
Operators picking among equivalents can read the shape (filter vs portfolio scale vs score-normalisation) and pick the one whose mechanism they trust on their real data.
What this catalog is not
- Not a recommendation set. Every strategy here ships with citation discipline (ADR-0011/0015) but the platform makes no claim that any of them currently captures alpha. The A/B harness is the place to ask that question; the catalog is the working surface.
- Not exhaustive. A risk-parity cross-sectional shape
(
XsRiskParityStrategy), a pairs-trade shape, a regime- switching wrapper — natural follow-ups, none shipped. The catalog grows as the research-question pipeline produces specific shapes worth registering. - Not a leaderboard. Operators sort the catalog by their own
question; the platform sorts by registration order. The
ak strategies listcommand is alphabetical by class name.
What gets added next
Whatever the next research question demands. The platform’s
strategy registration cost is now ~150 LOC + tests + an entry
in __all__ + a row in the citation graph. The bar for “is
this question worth registering a strategy for?” is the same
bar the
dont-pay-for-caution-you-cant-justify
note names — does the question have a measurable answer, and
does the answer warrant a separate shipped artifact?
If yes, the strategy ships. The catalog grows. The 6-arm harness gets another arm. The citation graph stays honest.