Apex++GAF-DC2: specification

A momentum rotation in large US stocks with accelerating revenue, plus a gated 3x Nasdaq-100 ETF sleeve, run in a US margin account. Rules, backtest, risks and a daily trade log.

1. What it does

The exact specification is in section 6.

2. Why it works

Momentum and growth. Stocks in strong trends tend to keep going for months. Requiring accelerating revenue drops trends that the business does not back. The cash and distress filters drop fragile balance sheets. Cap-squared weights tilt the book toward the largest leaders.

The post-2008 regime. The backtest starts on 2010-02-11, TQQQ's first trading day, and covers only this regime. Rules and policies in effect during it:

A daily-reset 3x ETF loses most in long, choppy declines, where volatility decay compounds. The trading rules above are designed to slow disorderly selling in single stocks and the whole market. The gate takes the sleeve out when QQQ's volatility rises.

Limits: these rules do not stop bear markets. In 2022 the Nasdaq-100 fell about 33% and TQQQ about 79%. Regimes can change.

3. Results

In-sample backtest, 2010-02-11 to 2026-09-18. Returns include 5 bps per side trading costs, borrowing costs and the margin checks below. Strategy rules and the evaluation period were selected using these data, so results carry selection bias.

Two margin models. Headline: the concentration-stress margin model in section 6. Second: Robinhood-style standard margin (25% maintenance on stocks, 75% on TQQQ, 50% initial; borrowing at the fed funds target upper bound + 1.25% to $50,000, + 1.05% to $100,000, + 0.75% to $1,000,000; first $1,000 free; no interest on cash). Both check maintenance at every close and at the daily lows.

CAGRMaxDDRolling 4y medianRolling 4y 10th pctWorst 4yMargin breaches
Apex++GAF-DC293.1%-59.1% (2011-02-14 to 2011-11-25)79.2%59.0%+40.5%1
Same, Robinhood-style margin88.9%-57.8% (2024-12-24 to 2025-04-08)77.9%54.6%+38.2%0

The headline model's one margin breach is at the daily low of 2021-03-05; the backtest sells pro rata at the next open to restore maintenance (section 6) and continues.

Rolling windows: 151 four-year windows, one starting on the first session of each month from 2010-03 to 2022-09. They overlap.

Growth of $12010-02-11 to 2026-09-18. Daily closing values normalized to the first close. Strategy includes trading costs and financing; ETFs show buy-and-hold total returns. image/svg+xml Independent strategy charts 2010 2012 2014 2016 2018 2020 2022 2024 2026 $1 $10 $100 $1,000 $10,000 $100,000 Value (log scale) Growth of $1 Apex++GAF-DC2 SPY QQQ TQQQ

Daily closing values start at $1. ETF benchmarks show buy-and-hold total returns.

Rolling four-year CAGRMonthly starts from March 2010 to September 2022. Each window uses the existing portfolio at the first session of the month and ends on the first session at least four calendar years later. Overlapping windows are dependent. image/svg+xml Independent strategy charts 2012 2014 2016 2018 2020 2022 Window start 0% 20% 40% 60% 80% 100% 120% 140% Annualized return Rolling four-year CAGR Apex++GAF-DC2 SPY QQQ TQQQ

Calendar-year returns (headline model):

2010 (from 02-11)20112012201320142015201620172018
+142%-34%+124%+364%+38%+88%+4%+175%-11%
20192020202120222023202420252026 (to 09-18)
+91%+323%+117%-42%+115%+367%+42%+257%

2022 onward. From 2022-01-03 to 2026-09-18 the CAGR is 106.2% (Robinhood-style margin: 101.0%). The rank buffer and the volatility target were chosen on the full history, including these years, so this is not a clean out-of-sample test.

Sensitivity tests. Each change applied separately (base 93.6%).

TestCAGR
Trading costs of 10 bps per side92.3%
Trading costs of 25 bps per side88.3%
All borrowing at fed funds + 3.00%, zero interest on cash90.2%
NVDA excluded82.4%
Five largest contributors excluded46.2%
Half target exposure49.2% (MaxDD -32.6%)

Walk-forward

Each January from 2014 to 2025, the rule set with the best average one-year return over January starts from 2011 to the prior year is picked and run for the next year in a fresh account. The 12 one-year returns are compounded. Robinhood-style margin.

Rule setsPickedCompounded yearly return
Apex++GAF (no cash or distress filters, buffer 12), fixed-62.7%
Apex++GAF vs DC2 at buffer 12DC2 in 12 of 12 years68.7%
Apex++GAF vs DC2 at buffer 12 vs DC2 at buffer 7buffer 7 in 2014 and 2019-202569.6%
The same three vs DC2 at buffer 7 with a 70% volatility target70% target in 2019-202572.5%
DC2 at buffer 7: 60% vs 70% volatility target70% in 11 of 12 years75.5%
DC2 at buffer 7, 70% volatility target (current rules), fixed-75.6%
DC2 without the TQQQ sleeve, fixed-58.2%
No TQQQ sleeve vs gated TQQQ sleevegated sleeve in 12 of 12 years75.6%

Data integrity

4. Risks

5. Trade log

Daily trade log: every backtest trading day (date, ticker, buy or sell, weight before and after as % of equity, reason) and the live log, updated after each nightly run. Weights only; no prices, share counts or account amounts.

6. Exact specification

Data

ItemRequired data
Stock pricesDaily open, high, low, close, adjusted for splits and dividends (total return)
UniversePoint-in-time S&P 500 and Nasdaq-100 membership (constituents as of each date, including later-delisted names)
Market capPoint-in-time company market cap (all share classes)
QQQ, TQQQDaily total-return open, high, low, close
FundamentalsQuarterly figures as originally reported: revenue, assets, cash, debt, net income, current ratio, calendar quarter and filing date
Fed fundsEffective federal funds rate
Period2010-02-11 (first TQQQ session) to 2026-09-18

Account and costs

Timing

ItemDecided onTrades at
Stock sleeve picks, weights, vol scaleclose of day t-1open of day t
Stock sleeve rebalanceevery 20 sessions per sleeveopen
TQQQ vol gateevery session, close of day t-1open of day t, the session after it flips
TQQQ resize to 0.5 x equity while on11th session of each monthopen

Rules

STOCK BOOK: 4 sleeves, each 1/4 of equity
  Sleeve k (k = 0..3) rebalances on sessions 5k, 5k+20, 5k+40, ...
  counted from 2010-02-11 (session 0).

  On a sleeve's rebalance, using data through the prior close:
    universe = point-in-time S&P 500 + Nasdaq-100 members; one share
               class per company (the higher-ranked class)
    eligible = close > SMA200 and SMA200 > its value 20 sessions earlier
               and growth_accel > 0 (see Growth-acceleration filter)
               and cash_ok and distress_ok (see Cash and distress filters)
    rank     = EMA50 / EMA200 of the close, highest first, eligible names only
    picks    = keep each name the sleeve already holds while it is eligible
               and ranked 7 or better; fill the remaining slots, up to 4
               names, with the highest-ranked eligible names not yet held
    w_i      = cap_i^2 / sum of cap^2 over the picks
               (cap = point-in-time company market cap)
    basket_vol = sample stdev (ddof 1) of the last 20 daily returns of the
                 portfolio sum(w_i * r_i), annualized x sqrt(252)
                 (r = simple daily total returns of the picks)
    scale    = clip(0.70 / basket_vol, 0.0, 1.5)
    target_i = (equity at today's open / 4) * w_i * scale
  Between rebalances, sleeve positions are not traded (they drift).

TQQQ SLEEVE
  qqq_vol = sample stdev (ddof 1) of the last 20 daily QQQ total returns
            x sqrt(252), on the prior close
  gate starts ON
  if ON  and qqq_vol > 0.32: OFF -> sell all TQQQ at the open
  if OFF and qqq_vol < 0.28: ON  -> buy TQQQ to 0.50 x equity at the open
  (between 0.28 and 0.32 the gate keeps its state)
  While ON, also trade TQQQ to 0.50 x equity on the 11th session of
  each month.

CASH
  cash = equity - stocks - TQQQ. Negative cash is a margin loan.
  At each rebalance at most 2.0x equity (1.5 stocks + 0.5 TQQQ); positions
  drift between rebalances.

DELISTING
  A held stock whose price series ends is converted to cash at the next
  open: at its last close when the delisting is an acquisition or merger
  (the deal consideration, cash and/or acquirer stock), and at 0 for any
  other cause (bankruptcy, regulatory or voluntary delisting, unknown),
  per the corporate-actions records. A stock with a gap in its
  prices that later trades again is converted at its last close.

Growth-acceleration filter

Use revenue as originally reported for each calendar quarter. In the formulas, calendardate identifies the quarter and datekey is the filing date. A report becomes available on the first trading session after filing.

For each company, one report per calendardate quarter (if duplicated, keep the earliest datekey).
growth(q)       = revenue(q) / revenue(q-4) - 1          (requires revenue(q-4) > 0)
growth_accel(q) = growth(q) - growth(q-1)
  q-k = the report whose calendardate is exactly k quarters before q, and
        whose datekey is on or before q's datekey. Otherwise growth_accel is missing.

Point in time:
  A report's value is usable from the first trading session strictly after its datekey.
  It is carried forward until the company's next report becomes usable,
  for at most 315 sessions; after that it is missing.
  A secondary share class with no SF1 rows uses its company key's rows (GOOG -> GOOGL).

Eligibility:  growth_accel > 0.
  A missing value makes the stock ineligible.

The filter only removes names; the rank stays EMA50 / EMA200.

Cash and distress filters

Use quarterly reports as originally filed. The comparison pool is reports filed in the preceding 90 calendar days by companies already in the index universe by the filing date. Share classes map to one company; GOOG uses GOOGL's reports.

For each company, one report per calendardate quarter (if duplicated, keep the earliest date).
Per report (dk = its filing date):
  A        = assets                                   (missing unless assets > 0)
  cash     = cashneq / A
  distress = debt / A - netinc / A - currentratio
  Any missing input -> that value is missing.

Flag, fixed once at filing:
  known(c, dk) = company c (its company key, the primary share class) was in the
                 point-in-time stock universe -- an S&P 500 or Nasdaq-100 member
                 with a price on that session, exactly the universe the stock
                 selection uses -- on at least one trading session dated on or
                 before dk (any share class of c counts)
  pool_x(dk)   = the reports of the report universe with a non-missing x, a filing
                 date in [dk - 90 calendar days, dk], and a company c with
                 known(c, dk) (the report being flagged is in its own pool only
                 if its company is known by dk; it is flagged either way)
  cash_ok      = cash     >  50th percentile of pool_cash(dk)
  distress_ok  = distress <  90th percentile of pool_distress(dk)
  Percentile: linear interpolation between closest ranks (numpy.percentile default).
  A report with a missing cash (distress) value has no cash (distress) flag; it is
  skipped, and the company's previous report with a value keeps applying.
  A report whose pool is empty has no flag (possible only before 1998-01-02).

Point in time (as GAF, per flag):
  A report's flag is usable from the first trading session strictly after dk.
  It is carried forward until the company's next report with that value becomes
  usable, for at most 315 sessions; after that it is missing.
  A secondary share class with no SF1 rows uses its company key's rows.

Eligibility (added to Apex++GAF's):  cash_ok AND distress_ok.
  A missing flag makes the stock ineligible.

A filtered stock is neither bought nor kept by the buffer.

Margin and concentration assumptions

These formulas set the headline backtest's limits on borrowing and concentrated positions. Real brokers' leverage and financing can differ.

maintenance = max( 0.25 x stock value + 0.75 x TQQQ value,
                   div(n) x sum_i stress_i x stock_value_i )
  n        = number of distinct companies held
  div(n)   = 1.00 for n <= 2, 0.95 for 3-5, 0.75 for 6-9, 0.60 for 10+
  stress_i = min(1, max(0.30,
                        0.30 + 0.065 x max(0, ret1y_i - 0.50),
                        0.50 x vol30_i))
  ret1y_i  = 252-session total return
  vol30_i  = population stdev (ddof 0) of the last 30 daily log returns x sqrt(252)

initial margin on any purchase:
  equity >= max(0.50 x long market value, maintenance rule sum, 1.1 x stress term)
  after the trade; purchases are scaled down pro rata to satisfy it.

maintenance check: at every close, and at the daily lows (all positions
marked at their low). A deficit is a breach: at the next open, sell all
positions pro rata until equity >= 1.10 x maintenance.

7. Changelog