opendeviationbar · feature-building · plain-English explainer
bar_close columns, all live in ClickHouse with COMMENTs: bar_hoeffding_phi_squared_midreturn_duration (#568, card 78), bar_vg_time_directed_clustering_meangap (#570, card 60) and bar_hvg_forward_visibility_horizon_mean (#579, card 59). So §7's “12 contributed columns” and §4's “latest: batch 5” both undercount. Canonical count is crates/opendeviationbar-core/data/feature_manifest.toml → bar_close (15), cross-checked by bar_close_schema_contract_four_sources_agree. Nothing else on this page has been altered — the promotion evidence for the 12 described columns stands as written. The badge on §6's Rotation Orthogonal Probe (NOT OPERATIONAL) also predates #676 “make the rotation and legacy probes operational”, which is merged; that one needs the author's confirmation rather than a mechanical edit.A walkthrough, in my own words, of what I have been doing: how I find a candidate feature, how I decide it is worth keeping (genuinely new, not a re-labelled copy of something we already have), how I check that judgement holds up as the market changes, and how I turn a survivor into a real production column I can trust. Every claim links to the page that grounds it.
The strategy already has a large panel of feature columns. Adding another column is only worth it if it tells us something the panel does not already tell us. So the whole job is a filter: take a long list of candidate features, and keep only the ones that are (a) orthogonal — genuinely new information, (b) parameter-free — no hand-tuned magic numbers, and (c) agnostic — one well-defined algorithm two honest people would implement the same way. Those three tests are the Three-Axis Probes, and one gate combines them into a single keep / skip decision.
Does it tell us something no existing column already does? Measured on real bars, across symbols and regimes.
No secret tuned numbers, no if window≥500 switch. Runs first because it is free.
One algorithm — two correct implementations converge to the same answer (~1e-9).
keep = orthogonal ∧ parameterless ∧ agnostic. A tunable knob vetoes everything.
I never trust a feature because its paper says it is novel — I measure its redundancy on our own bars. The metrics fall into three buckets: the operational ones that actually decide the verdict today, a complementary second check that is built but not yet wired into the decision, and the ones that are only reported, never gating.
The real in-production screen: "is this candidate new information vs the columns we already ship?", scored on real bars, worst-case across market regimes. Important: crypto and forex were screened by two different probes — so I show them separately, exactly as they ran.
orthogonality_probe.py (crypto-only since 2026-05-30). Scored across crypto symbols × all production thresholds × 21 two-month slices grouped into 7 regime epochs (a candidate must hold up in every epoch). The gate is Spearman |ρ| + h_norm — that is all the probe computes. Chatterjee ξ appears in the code only as a deferred extension marked "intentionally NOT wired in" — it is not computed on crypto.
| Metric | What it asks | Role |
|---|---|---|
| Spearman |ρ| | A rank / monotone copy of a shipped column? | GATES. Declared Spearman ρ bands: ≤0.85 orthogonal · 0.85–0.95 WATCH · >0.95 BAN. |
| h_norm | Does the column collapse to near-constant? | GATES. <0.05 = constant-like → rejected. |
| Chatterjee ξ | — | Not computed by the crypto probe (deferred extension). |
median max|ρ| ≤ 0.85 AND pooled-pass ≥ 60% AND min-regime-pass ≥ 50%. The earlier bar_close features (petrosian/katz FD, dispersion entropy, CECP velocity) passed an older, stricter harness that additionally gated on R² ≤ 0.85 (panel / leave-out reconstructability) — a tougher bar the named probe does not carry.multislice_orthogonality_probe.py (a separate, two-stage pipeline). The crypto probe does not cover forex, so the 13 forex features were screened by a different tool across 4 FX / metal symbols × 1–50 dbps × event episodes + intraday sessions (Asian / London-NY).
| Stage | What it does | Role |
|---|---|---|
| 1 · Spearman screen | Same ρ bands as crypto (BAN >0.95 · WATCH 0.85–0.95) + h_norm / degeneracy | Shortlists survivors. |
| 2 · Chatterjee ξ keeper gate | Asymmetric ξ vs production, per-symbol median, with cross-symbol replication | GATES. ξ > 0.50 per-symbol-median + ≥2-symbol replication → absorb/drop; else independent. implementation_ready flips true only after ξ passes. |
<0.30 independent · 0.30–0.50 WATCH · >0.50 absorb) — the opposite of crypto, where ξ is not even computed. All 13 came out independent (per-symbol median ξ ≤ 0.29).0.85 / 0.95 are Spearman ρ bands, declared project constants (constants_registry.toml: WATCH_LO=0.85, BAN_HI=0.95); the forex ξ gate uses a different scale (0.50 on ξ). Whether crypto's 0.85 is "principled" vs a chosen policy is a separate meta-evaluation question (matrix-eval iter 7: policy, not derived), not part of this operational decision.A different axis: instead of "new vs production", it asks "is this candidate redundant with the other candidates in the batch?", to weed out near-duplicates among the new features. Terry classes this as a 2nd-layer / complementary check — explicitly not a meta-evaluation. It lives only inside the rotation probe (rotating_slice_orthogonality_probe.py), which is not wired into the operational decision.
| Metric | What it asks | Why we use it |
|---|---|---|
| Leave-out R² (LOO-R²) | How well can the other candidates predict this one? | Regress the candidate on its siblings; high R² = the others already explain it → it adds nothing. Removes candidates redundant with each other. |
| max sibling |ρ| | What is its single closest sibling? | Pairwise sibling redundancy — the nearest twin among the candidates being considered. |
How the rotation probe scores (also not operational): each candidate is tested across many strata — its grid is asset class × symbol × threshold × volatility × session × trend, run across both forex and crypto — and only a candidate that survives the hardest stratum and repeats in both markets is kept. Here "asset class" = crypto vs forex, and it is a dimension only in this probe — the operational probe above is crypto-only. Detector sanity check: a shipped feature scored against itself returns ρ ≈ ξ ≈ LOO-R² ≈ 1.0 — it correctly flags a perfect duplicate.
| Metric | What it is used for |
|---|---|
| W1 (Wasserstein-1) distribution view | Report-only. The verdict collapses every cell to the single worst ("redundant somewhere?"); W1 reports the mean across cells ("redundant everywhere?"). It explains whether a worst-cell hit is a regime-local spike or broad redundancy — but it never gates. |
| CODEC · O-information | Higher-order / conditional redundancy given the rest of the panel. Measured and held (reported), not gated — there is no faithful FOSS null yet, so they inform, they do not decide. |
References: the operational decision is the orthogonal dashboard (gating metrics + the report-only distribution view); the complementary LOO-R² check is the rotation probe; see also slicing methodology and the named regime slices.
I do not invent a new engineering path each time. I review the previous implementations and follow the same robustness standard, building the new feature step by step in an autonomous loop. The loop walks a feature from "trusted formula on paper" toward a live, backfilled production column — but it never merges, deploys, or backfills by itself: it stops at an open PR, and a human takes it the rest of the way.
Stages ①–③ are the autonomous loop (detailed in §4). Stages ④–⑦ are operator-gated: the human merges, deploys with mise run deploy:bigblack (builds + installs under the odb service account), restarts the sidecar so new live bars carry the column, then runs the historical backfill so it also fills back across history — consistent at the live↔historical boundary. (Forex is the same shape from /opt/mql5 → fxview-sidecar.)
Once the loop reaches its open PR, I close it out in four steps (these are the loop's own P2 / P3 phases plus my operator read):
Crypto and forex run as two separate autonomous campaigns, each with its own pipeline. They share the same discipline (bit-exact oracle → causal Rust kernel → full wiring → adversarial challenge) but differ in shape: crypto runs a 16-stage-per-feature pipeline across four phases; forex runs a leaner per-feature lane with stacked PRs.
Four campaign phases. Inside P1, each feature walks all 16 stages before the next begins; then the whole batch is verified and adversarially challenged.
The 16 per-feature stages inside P1 (in order):
| Stage group | Stages | Plain meaning |
|---|---|---|
| Prove the maths | oracle · xcheck | Match a trusted reference bit-exactly, then cross-check against a second independent implementation. |
| Build the kernel | kernel · wire · causality · determinism | Fast Rust kernel, threaded through the bar struct / API / writer; proven to read only past bars and give the same answer every run. |
| Store it | schema · contract · manifest | Add the ClickHouse column (DDL + comment), column-count / type tripwires, and register it in the feature catalogue. |
| Verify it | parity · robust | Streaming output equals batch output; degenerate inputs and oversized windows are handled (robustness witnesses). |
| Ship it | adr · mise · checkfull · challenge · commit | Decision record, slash-commands, the full quality gate (fmt + lint + test + deny), the adversarial Attacker/Defender audit, then open the PR — the loop stops here. |
Forex runs one lane per feature, each stacked on the previous PR; schema and code ship together in a single PR (no split-brain).
Both flows then enter the operator-gated tail in §3 (merge → deploy → sidecar restart → backfill). Source campaigns are the newest in the dashboard: crypto 2026-06-19-bar-orth-batch5-implementation (PR #544) and forex 2026-06-24-forex-batch34-rqw-crex-implementation (PRs #124 / #126 / #127). Browse from the crypto and forex candidate hubs.
The current, operational path a crypto feature actually travels, end to end. Green = running today; amber = a human must trigger it (the loop stops at the PR and never auto-deploys); grey = not in this chain.
Beyond implementing individual features, recent work has been about strengthening the orthogonality judgement and looking ahead — a forward-looking probe, a complementary cross-check, and a hardened candidate registry. Important: these are research / evaluation surfaces — only the production decision in §2 is operational today; the three below are not yet wired into the live gate. Each is grounded in a page you can open:
Asks whether a feature that is orthogonal today stays orthogonal tomorrow. Grounded by an out-of-sample walk-forward (replicated): orthogonal-today features persist ~94–95% into the next regime, with a declared set bounded at FDR ≤ 10%. Why it is effective: it turns "independent now" into a regime-scoped, error-bounded bet instead of a forever-claim — and it is honest that 0 of 92 features are invariant across all regimes, so every declaration carries a regime scope. The live expiry monitor is specified but not yet built (hence EVALUATING).
Hardens the candidate registry and turns the manual "is this already covered?" novelty check into a fast, automatic, evidence-backed uniqueness pre-filter with a tamper-evident, hash-chained history. Why it is effective: it screens a candidate for uniqueness against everything already catalogued before spending the expensive empirical sweep — so duplicates and near-duplicates are caught at registry level, and the costly orthogonality screen is reserved for genuinely novel candidates.
The rotating-slice probe tests a candidate across every market condition (strata) and fuses both redundancy layers per stratum: vs production (Spearman |ρ| + Chatterjee ξ) and vs siblings (Leave-out R² + max sibling-|ρ|). A candidate passes only if it survives the worst stratum and replicates across forex + crypto. Why it is effective: the worst-stratum rule kills one-regime flukes, and the LOO-R² layer removes candidates redundant with each other — the exact second layer described in §2.
Reference note: none of these three is wired into the operational gate yet — the forward probe and rotation probe are EVALUATING, and the candidate registry is a hardening campaign over a tracking ledger. Only the production decision in §2 is operational today.
The complementary cross-check, step by step (built, not wired into the live gate). The cyan callouts flag where the crypto and forex orthogonality probes genuinely differ.
How a candidate would flow from an idea to a live column through the hardened registry. The key idea: a cheap novelty pre-filter (is it already in our catalogue?) is a different gate from the expensive orthogonality test (does it add new information?).
Full transparency on what shipped and the exact bar each one cleared. There is no single promotion standard — three were used, and they differ by group:
orthogonality_probe.py: median|ρ| ≤ 0.85 ∧ pooled-pass ≥ 60% ∧ min-regime-pass ≥ 50% (Spearman |ρ| + h_norm; ξ not computed).R² ≤ 0.85 (worst-valid-cell, ~10 slices).ξ > 0.50 per-symbol-median + ≥2-symbol replication.| Feature | How it was promoted |
|---|---|
bar_close group · PR #509 / #515 / CECP campaign · predecessor fractal / entropy / CECP harness · gate ρ≤0.85 ∧ R²≤0.85 ∧ h_norm≥0.05 (worst-valid-cell, ~10 slices) — stricter than the named probe; pre-dates it | |
bar_petrosian_fd | PR #509; promoted as a panel column, re-confirmed KEEP later by the literal probe (median |ρ| 0.306) |
bar_katz_fd | PR #509; the weakest KEEP — min-regime |ρ| 0.86 (touches the WATCH band in some regimes) |
bar_dispersion_entropy | PR #515; entropy-spike clone (orthogonality_probe_full_ch.py) — also gated on LOO-R² + combinatorial-R² |
bar_cecp_velocity | CECP campaign (2026-06-10); ρ≤0.85 ∧ R²≤0.85 ∧ h_norm≥0.05 |
batch-5 · PR #544 · the literal orthogonality_probe.py (441 cells = 21 symbol×threshold × 21 slices; Spearman |ρ| + h_norm; ξ NOT computed) · Median Rule: median|ρ|≤0.85 ∧ pooled-pass≥60% ∧ min-regime-pass≥50% | |
bar_categorical_recurrence_rate | Median Rule KEEP |
bar_sign_markov_flux | Median Rule KEEP |
bar_ramsey_rothman_bicov_lag1 | Median Rule KEEP |
bar_ehlers_increment_asymmetry | Median Rule KEEP |
bar_cox_stuart_trend_z | Median Rule KEEP |
bar_groeneveld_meeden_b3_skewness | Median Rule KEEP |
bar_l_kurtosis_tau4 | Median Rule KEEP (max |ρ| 0.872 in an isolated cell — clears the median rule) |
bar_bartels_rank_vn_ratio | Median Rule KEEP |
| Feature | How it was promoted |
|---|---|
batch 1–2 · PRs #91–#99 · multislice_orthogonality_probe.py (Stage 1 Spearman screen → Stage 2 ξ keeper gate) · 10 slices (8 episodes + 2 sessions) · ξ keeper gate: ξ>0.50 per-symbol-median + ≥2-symbol replication → all came out independent (median ξ ≤ 0.29) · 9 shipped as columns #1–9 (5 deferred) | |
anderson_darling_a2 | ξ-confirmed independent |
edge_spread_bps | ξ-confirmed independent |
hvg_clustering | ξ-confirmed independent |
kendall_taub_ret_spread | ξ-confirmed independent |
lziv_complexity_signs | ξ-confirmed independent |
mann_kendall_z | ξ-confirmed independent; stands in for a 4-way monotone-twin clique (the others dropped as duplicates) |
sevcik_fd | ξ-confirmed independent (a worst-cell ξ 0.526 was ignored — not replicated across ≥2 symbols) |
sign_two_state_entropy_rate | ξ-confirmed independent |
spectral_log_slope | ξ-confirmed independent |
| batch 3–4 · forex batch34 · same two-stage probe, run on the crossed regime×session 24-slice panel (341 cell-slices) · same ξ keeper gate (median ξ ~0.13) · 4 shipped as columns #10–13 (of 15 ξ-cleared) | |
pomeau_irreversibility_lag1 | ξ-confirmed independent |
hvg_degree_assortativity_coefficient | ξ-confirmed independent |
hvg_mean_shortest_path_length | ξ-confirmed independent |
psd_wiener_spectral_flatness | ξ-confirmed independent |
Honest notes: (1) the FD pair (bar_petrosian_fd / bar_katz_fd) were promoted before orthogonality_probe.py existed — their "re-confirmed by the probe" rests on antropy determinism (recompute == materialized is asserted, not measured). (2) On the counts: the batch-1/2 ξ stage produced 14 ξ-confirmed keepers (13 KEEP + mann_kendall_z as the direction-clique representative), of which only 9 became live columns (5 deferred — substrate / parameter-blocked); batch 3-4 ξ-cleared 15, of which 4 shipped. The 13 contributed columns on this page are those 9 + 4, and mann_kendall_z is one of the 9 (column #6) — not an extra on top of the 13. Full per-column reference: forex feature catalog.