Apex++GAF: specification
A momentum rotation into the 4 strongest S&P 500 / Nasdaq-100 stocks whose revenue growth is accelerating, sized to a 50% volatility target, plus a 0.5x equity TQQQ sleeve. The sleeve is held only while QQQ's 20-day volatility is low. Account: US margin account at Interactive Brokers.
Data
| Item | Source |
|---|---|
| Stock prices | Daily open, high, low, close, adjusted for splits and dividends (total return) |
| Universe | Point-in-time S&P 500 and Nasdaq-100 membership (constituents as of each date, including later-delisted names) |
| Market cap | Point-in-time company market cap (all share classes) |
| QQQ, TQQQ | Daily total-return open, high, low, close |
| Fundamentals | Sharadar SF1, quarterly as-reported (ARQ): revenue, calendar quarter, filing date (column date) |
| Fed funds | Effective federal funds rate (FRED DFF) |
| Period | 2010-02-11 (first TQQQ session) to 2026-09-18 |
Account and costs
- Starting equity $100,000. On 2010-02-11 (session 0) the TQQQ sleeve and stock sleeve 0 are filled at the open, decided on the 2010-02-10 close. Sleeves 1-3 hold cash until their first rebalance (2010-02-19, 2010-02-26, 2010-03-05).
- Trading cost: 5 bps per side on traded notional. No taxes.
- Margin loan rate: fed funds + 1.50% on the first $100,000 borrowed, + 1.00% up to $1,000,000, + 0.75% above. Blended, 360-day year.
- Cash credit: fed funds - 0.50% on cash above $10,000; when equity is below $100,000, scaled by equity / $100,000.
Timing
| Item | Decided on | Trades at |
|---|---|---|
| Stock sleeve picks, weights, vol scale | close of day t-1 | open of day t |
| Stock sleeve rebalance | every 20 sessions per sleeve | open |
| TQQQ vol gate | every session, close of day t-1 | open of day t, the session after it flips |
| TQQQ resize to 0.5 x equity while on | 11th session of each month | open |
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)
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 12 or better; fill the remaining slots, up to 4
names, with the highest-ranked eligible names not yet held
w_i = cap_i^1.5 / sum of cap^1.5 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.50 / 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.
Maximum gross exposure 2.0x equity (1.5 stocks + 0.5 TQQQ).
DELISTING
A held stock with no price on a session is converted to cash at its
last close.
Growth-acceleration filter
Data: Sharadar SF1 (fundamentals table, the full bulk download fundamentals.csv.zip, or the API), dimension ARQ (as-reported quarterly), fields revenue, calendardate and the filing date. The current Sharadar API and bulk files name the filing-date column date; older documentation calls it datekey. Example: ticker A, calendardate 1999-09-30, date 2000-01-25, reportperiod 1999-10-31.
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 rank stays EMA50 / EMA200. The filter only removes names.
Margin model (IBKR Reg T with concentration stress)
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.
Results
Sharadar data, step-2 engine, IBKR margin model, 2026-10-07.
In-sample backtest, 2010-02-11 to 2026-09-18 (the filter was chosen after seeing this period):
| CAGR | MaxDD | Rolling 4y mean / median | Worst 4y | Margin breaches | |
|---|---|---|---|---|---|
| Apex++GAF | 71.4% | -62.1% | 66.6% / 65.6% | +35.1% | 1 (2010-05-06) |
| Apex++ | 63.1% | -68.8% | 62.2% / 63.2% | +23.0% | 1 (2010-05-06) |
Walk-forward test: filter on or off, chosen with training data only (expanding training from 1999-03-15; test periods 2007-10, 2011-14, 2015-18, 2019-22, 2023-26):
| Test period | Choice | Training score without / with filter |
|---|---|---|
| 2007-2010 | Apex++ | 39.1 / 11.1 |
| 2011-2014 | Apex++ | 19.0 / 6.4 |
| 2015-2018 | Apex++ | 17.0 / 10.0 |
| 2019-2022 | Apex++ | 27.8 / 24.9 |
| 2023-2026 | Apex++GAF | 33.1 / 33.4 |
| 2007-2026, books started 1999-03-15 | Rolling 4y mean / median | Worst 4y | CAGR | MaxDD |
|---|---|---|---|---|
| Walk-forward choice (out-of-sample) | 49.0% / 52.9% | -23.5% | 46.9% | -83.0% |
| Apex++GAF fixed | 55.7% / 59.0% | -27.9% | 53.9% | -84.7% |
| Apex++ fixed | 52.6% / 54.4% | -23.5% | 49.3% | -83.0% |
The filter lowered the 1999-2006 training score, mostly in the 2000-2002 bust. From 2007 it raised returns.
Required outputs for comparison
Report these, computed independently:
- Gate switch list: decision date, trade date, new state.
- Picks with weights for each sleeve on its first rebalance on or after each Jan 2 from 2011 to 2026.
- Calendar-year returns, 2010 to 2026.
- CAGR, maximum drawdown (with peak and trough dates), and every margin breach date.
- Rolling 4-year CAGR windows starting on the first session of each month from 2010-03 to 2022-09: mean, median and worst.