z-of-a.

The GA doesn't have enough to chew on. That's the finding.

Walk-forward validation across three models and three horizons. AUC hovers near 0.5. The cycle is real — but not point-predictive in the feature space we have.

We built a spectral macro synthesis engine. It decomposes market data into four frequency bands, tracks a ~2-year credit-volatility cycle, and produces daily LLM-narrated briefings through a 3-model pipeline. Yesterday we asked the obvious next question: should the genetic algorithm search for multi-frequency patterns in these spectral features?

We ran the test. The answer is no — not because the approach is wrong, but because the feature space doesn’t contain enough predictive signal to justify the search.

The test

Three models, walk-forward validated on 76 years of S&P 500 data. The target: predict whether realized volatility will spike above its 75th percentile within the next 21, 63, or 126 trading days.

Model A (2yr band only): phase, envelope, and rate of change from the ~788-day credit cycle. Three features. This is the signal that survived every test in the astrology work.

Model B (all four bands): same three features from each of the quarterly, annual, 2-year, and business cycle bands. Twelve features. If multi-frequency resonance patterns exist, this model should capture them.

Model C (cross-asset): the 2yr band from S&P 500 plus the 2yr band from HYG (high-yield bonds), 10-year Treasuries, and VIX. Twelve features. If cross-asset lead-lag relationships add predictive power beyond the single-asset cycle, this should show it.

Walk-forward validation: train on 10 years, test on 2 years, roll forward. Twenty-seven windows covering the full dataset. Logistic regression with L2 regularization. Metric: AUC-ROC.

The results

HorizonModel A (2yr)Model B (all bands)Model C (cross-asset)
21 days0.4480.5300.472
63 days0.5050.5380.426
126 days0.4510.4930.443

An AUC of 0.5 is random chance. All three models are near that line.

Model B (all bands) trends slightly higher at the 21-day horizon (+0.08 AUC over Model A, p = 0.09), but the improvement is not statistically significant. Model C (cross-asset) adds nothing — the cross-asset 2yr bands are so correlated with S&P volatility (r = 0.975 for HYG, as we established) that they’re redundant.

What this means

The ~2-year credit cycle is real but not point-predictive. The Lomb-Scargle periodogram shows it. The cross-correlation cascade confirms it. The bandpass filter isolates it. The international replication validates it. But when you ask “given today’s cycle phase, will volatility spike within 21 days?” the answer is barely better than a coin flip.

This is not a contradiction. A real cycle can be detectable in frequency space without being exploitable by a classification model. The cycle has a mean period of 788 days with a standard deviation of 164 days. It wanders. It amplifies unpredictably. Knowing where you are in the cycle tells you the general direction (easing vs. stress) but not the timing of transitions. A logistic regression on phase and envelope can’t capture the nonlinear, regime-dependent dynamics that make transitions sharp.

Multi-frequency combinations trend better but not significantly. Adding the quarterly and annual bands provides marginal improvement — the 21-day AUC moves from 0.45 to 0.53. That’s suggestive. There may be multi-frequency resonance patterns where, say, the quarterly cycle is peaking while the 2-year cycle enters its rising phase. But the effect is too weak and too variable across windows for a linear model to extract reliably.

Cross-asset features are redundant, not complementary. HYG, TNX, and VIX in the 2-year band move so closely with S&P volatility that adding them is like measuring the same thing three times. The cross-correlation work from the previous post already showed this — r = 0.975 with HY bond vol means there’s almost no independent information to extract.

What this means for the GA

The genetic algorithm was designed to search for feature combinations that univariate and linear tests miss. The original plan: variable-length chromosomes encoding conjunctions of spectral conditions, evolved under parsimony pressure with an island model providing diverse search.

But a GA searching 36 features (9 tickers times 4 bands) for classification signal that linear methods can’t find at AUC > 0.55 is likely to overfit. The GA would find combinations that score well in-sample — it always does — but the validation pipeline (permutation test, out-of-sample, bootstrap CI) would kill them. We’ve been down this road. That earlier GA found patterns in S&P direction that the permutation test evaporated. The feature space has changed but the fundamental problem hasn’t: not enough signal for the complexity of the search.

The three options

Option 1: GA on position sizing, not classification. The backtest showed the cycle has value as a risk overlay — not predicting when volatility will spike, but modulating how much equity exposure to hold based on cycle phase. The GA could optimize the mapping from cycle phase to portfolio weight, searching for nonlinear position-sizing functions that improve Sharpe ratio. This is a smaller, better-defined problem with a continuous fitness function rather than binary classification.

Option 2: GA on a richer feature space. The spectral bands are four numbers per ticker. That may simply be too sparse. Options flow (put/call ratios, skew), credit default swap spreads, earnings revision momentum, FOMC meeting dates, macro surprise indices — these are fundamentally different information channels that the frequency decomposition can’t see. The GA could search for conjunctions across these richer features, using the spectral cycle phase as one input among many.

Option 3: Drop the GA, keep the engine. The spectral synthesis engine already works. It decomposes, detects regimes, narrates, produces daily briefings in five tones through a 3-model pipeline. The cycle signal has demonstrated value as a risk overlay (volatility reduction, drawdown protection). Maybe the right move is to ship the briefing product and treat the GA as a future enhancement for when the feature space is richer.

Where this leaves the project

The JLMoney arc now has two complete acts and an intermission:

Act 1 (astrology): tested the hypothesis honestly. Killed Saturn in Taurus, killed slow-planet aliasing, killed Mars causation. Found the ~788-day credit cycle as a genuine spectral feature.

Act 2 (spectral engine): built the Elixir engine. Daily pipeline: fetch 9 tickers, bandpass decompose into 4 bands, compute regime state, narrate via 3-model LLM pipeline with tone presets. Working product that generates daily briefings.

Intermission (this post): tested whether multi-frequency spectral features provide enough signal for the GA to search. Answer: not in their current form. The cycle is real but the predictive feature space is too sparse for combinatorial search.

Act 3 (next): either enrich the feature space with non-spectral data and point the GA at it, or optimize the existing signal for position sizing, or ship the briefing product as-is and iterate.

The methodology continues to work as designed: test, measure, report honestly, don’t build on top of signal that isn’t there.

The methodology

Feature extraction. Causal bandpass filters (IIR Butterworth, order 3) at four bands: quarterly (42–90 days), annual (180–400 days), two-year (600–1000 days), business cycle (1000–2000 days). Causal envelope and phase via derivative-based Hilbert approximation. Rolling z-score normalization with 1000-day lookback.

Target variable. Binary: does 21-day realized volatility exceed its rolling 75th percentile (10-year lookback) at any point within the prediction horizon? Tested at 21, 63, and 126 trading days.

Models. Logistic regression with L2 regularization (lambda = 0.01), implemented from scratch (gradient descent, 500 iterations). No sklearn dependency.

Validation. Walk-forward: 10-year train, 2-year test, stepped forward by 2 years. 27 windows. AUC-ROC computed per window. Paired t-test for model comparison.

Cross-asset alignment. HYG, ^TNX, and ^VIX aligned to S&P 500 trading dates via date-matching with forward-fill for missing dates.

← All Lab Notes