Retired Experiments
Swing Trader and Astro Lite are retired, in full — full logs, frozen final state, and an honest retirement note. Nothing here is deleted.
Astro Heavy
May 2026 – Oct 2026 · retired: the site moved from trading signals to scenario analysis
$100.99 final NAV · 48 trades
Swing Trader
late May 2026 (exact start unrecorded) – Jun 19, 2026 · died in the June outage
unrecorded final NAV · 0 trades
Astro Lite
late May 2026 (exact start unrecorded) – Jul 6, 2026 · retired: ablation superseded by pillar scoring
unrecorded final NAV · 2 trades
# Experiment Archive — Retirement Notes
PredictMyGold originally ran a three-bot ablation (Swing Trader, Astro Lite,
Astro Heavy) to test whether Vedic astrology signals add anything over pure
technical/regime trading. The owner has retired that ablation in favor of a
weighted, Brier-scored, four-pillar intelligence Ledger: every pillar
(including astrology) now files pre-registered, dated calls that are scored
against actual price outcomes, and its "earned weight" is published at
`/api/weights`. That per-call scoring is a more direct and continuously-updated
answer to "does astrology add anything?" than comparing three separate paper
accounts ever was.
Swing Trader and Astro Lite were retired in July 2026. **Astro Heavy was
retired in October 2026**, when PredictMyGold moved from trading signals to
scenario analysis (the gold price simulator is now the home page). Nothing
here is deleted; wrong or unflattering results are kept, not hidden.
## Astro Heavy (`bot_astro_heavy.py`) — retired October 2026
- **What stopped:** position sizing, rebalancing, stops and P&L tracking.
- **What did not stop:** everything analytical. Price, the weekly/daily
regime, RSI, MACD and ADX, the astro calendar, and the registration and
grading of astrology calls moved unchanged to `market_signals.py`
(indicators copied verbatim into `indicators.py`, with a test proving the
outputs are identical). The astrology pillar's track record continues
without a gap.
- **Final state:** the frozen `state_heavy.json` and `trades_astro_heavy.csv`
stay in the production data volume; the /experiments page reads its final
NAV and trade count from them directly.
---
## Swing Trader (`bot_swing.py`)
- **Strategy:** weekly-regime-gated swing trades (15-min check cycle), daily
regime + astro bias as an entry filter, technical trailing/hard stops.
- **Start:** operational since late May 2026. The exact first-cycle timestamp
was not preserved in any surviving log (no dated CSV row or state snapshot
from before June 1 survives in this repo).
- **End:** June 19, 2026 — `run_bots.py` had no restart logic; when the Swing
process died it was never restarted (see `README_UPGRADE.md`, "Silent
death, June 19"). Nothing detected or alerted on the outage.
- **Last recorded state:** cycle 58, updated 2026-06-01T18:11:37Z — see
`swing_final_state.json`. At that point: `balance_usdt=$50.00`,
`balance_paxg=0`, `portfolio_val=$50.00`, `pnl=$0.00` per the bot's own
state write.
- **Trade log:** `trades_swing.csv` does not exist anywhere in this repo —
no trade was ever appended to it, and `swing_trades.csv` is intentionally
**not** included here since there is nothing real to freeze. The state
file's `balance_usdt` ($50) does not match its own starting `CAPITAL`
($100) despite zero logged trades and zero PAXG held — that inconsistency
predates this retirement, was not introduced by it, and is not resolved by
this document. It is presented as-recorded, not corrected or explained away.
- **Trades executed:** 0 (per the missing CSV and `position_pct: 0` /
`balance_paxg: 0` in the last state).
- **Reason for retirement:** superseded by per-call Brier scoring of the
astrology pillar; one bot (Astro Heavy) remains for the live track record.
Swing's silent death on June 19 — and the fact that its own state hadn't
been refreshed since June 1, well before that death — was itself a symptom
of the monitoring gaps this rework closes (loud staleness badges, a
supervisor that actually restarts crashed bots, ops alerts to Telegram).
## Astro Lite (`bot_astro_lite.py`)
- **Strategy:** the same regime/astro framework as Swing but on an hourly
cycle, with a simplified position-sizing rule and Claude-authored planetary
briefs.
- **Start:** operational since late May 2026 (same caveat as above — exact
first cycle not preserved).
- **End:** July 6, 2026 (today) — retired as part of this rework, not a crash.
- **Last recorded state:** cycle 15, updated 2026-06-01T17:47:48Z — see
`lite_final_state.json`. `balance_usdt=$50.00`, `balance_paxg=0`,
`portfolio_val=$50.00`, `pnl=$0.00`. Like Swing, state hadn't refreshed
since June 1 even though the bot was nominally "live" until today — the
same silent-staleness pattern, undetected until this audit.
- **Trade log:** **Correction, 2026-07-07 (Phase 9 v2 audit):** this was
wrong. `trades_astro_lite.csv` did not exist *in this repo* at the time
this was written, but it existed on the real production DigitalOcean
volume this repo never had access to until the Azure migration. Real
log, now copied here as `lite_trades.csv`: a BUY at $4,309.72 (25%,
2026-06-07 16:43 UTC) and a SELL at $4,116.52 (back to 0%, 2026-06-23
11:53 UTC) — a real ~4.5% loss on the 25%-sized position, roughly -1%
of total capital. This does not reconcile with the ~$50 `portfolio_val`
in `lite_final_state.json` (see below); that figure is presented
as-recorded, not corrected, consistent with this document's own rule.
- **Trades executed:** 2 (see `lite_trades.csv`) — not 0 as originally
stated here.
- **Reason for retirement:** the three-bot ablation is superseded by per-call
Brier scoring of the astrology pillar; one bot remains for the live track
record.
---
## What's in this folder
| File | Contents |
|---|---|
| `swing_final_state.json` | Frozen copy of Swing's last `state_swing.json` (cycle 58, 2026-06-01). |
| `lite_final_state.json` | Frozen copy of Lite's last `state_lite.json` (cycle 15, 2026-06-01). |
| `lite_trades.csv` | **Added 2026-07-07** — Lite's real 2-trade log, recovered from the production DigitalOcean volume during the Azure migration (this repo never had it before). See the correction under Astro Lite above. |
| `code/bot_swing.py` | The exact code that produced Swing's trade history. No longer imported anywhere live. |
| `code/bot_astro_lite.py` | The exact code that produced Lite's trade history. No longer imported anywhere live. |
No `swing_trades.csv` is included — Swing genuinely logged zero trades
(confirmed against the real production volume too, not just this repo).
`lite_trades.csv` **is** now included (see above) — the "zero trades for
both bots" claim below is kept struck through rather than deleted, per
this document's own "nothing here is deleted" rule.
~~No `swing_trades.csv` / `lite_trades.csv` are included — both bots logged
zero trades before retirement, so there is no trade log to freeze.~~ If
this changes (e.g. an older trade CSV turns up elsewhere), it should be
added here rather than reconstructed — which is exactly what happened for
Lite.
# Honest Backtest Re-Run (2026-07-06)
`backtest_macro_v2.py` re-runs the same three-pass macro/astro backtest as
the archived `backtest_macro.py` (see `archive/experiments/code/`), over the
same 730-day PAXG/USDT window (2024-07-07 → 2026-07-06), with the two bugs
the audit found actually fixed:
1. **Weekly-candle look-ahead.** The old backtest's weekly slice was
`ww = [c for c in weekly if c["time"] <= wd[-1]["time"]]` — this includes
the *current, still-forming* weekly bar as soon as its **open** time is on
or before today, which leaks that week's not-yet-known final close into
mid-week decisions. `backtest_macro_v2.py` requires a full 7 days to have
elapsed since the bar opened (`c["time"] + timedelta(days=7) <=
wd[-1]["time"]`) before that bar is visible — the same `closed()`
discipline now used live in `bot_astro_heavy.py` via `signal_policy.py`.
2. **Zero trading costs.** The old backtest had no fee variable at all —
every rebalance was free. `backtest_macro_v2.py` applies `FEE = 0.0012`
(12bps per side) on every fill, the same `COST_BPS` used live.
## Old claim vs honest re-run
`bot_astro_heavy.py`'s docstring (and the dashboard's `backtest_pnl` /
`backtest_dd` fields) claimed **Pass C — Dynamic sizing + Vedic astro**
achieved:
| | Old claim (look-ahead, no fees) | Honest re-run (closed candles, 12bps fees) |
|---|---|---|
| Net P&L | +62.88% | **+38.42%** |
| Max drawdown | 14.40% | **17.42%** |
| Win rate | 69.1% | **57.4%** |
The gap is not noise — it's the two bugs. Removing the look-ahead alone
lets the strategy react to real, already-closed information instead of a
sneak preview of the current week's close; adding realistic fees on top of
102–113 rebalances per pass (vs. free trading before) compounds directly
into the P&L. **The honest number is meaningfully worse than advertised on
every metric**, and the archived `bot_astro_lite.py`'s own claimed
+57.94% is presumed to carry the same bugs (it was backtested with the
same pre-fix harness) — that file is left untouched as the frozen,
inspectable historical record of what the retired bot's authors believed
at the time (see `archive/experiments/RETIREMENT.md`); it is not re-run or
re-published as a current claim anywhere live.
## Full honest re-run — all three passes
Period: **2024-07-07 → 2026-07-06** (730 days) · Capital: $50 · Fee: 12bps/side
| Metric | A: Buy & Hold | B: Dynamic, no astro | C: Dynamic + astro |
|---|---|---|---|
| Net P&L % | **+65.67%** | +37.73% | +38.42% |
| Final value | $82.83 | $68.87 | $69.21 |
| Alpha vs Buy & Hold | +0.00% | **−27.94%** | **−27.25%** |
| Max drawdown | 27.74% | 15.48% | 17.42% |
| Win rate | n/a (0 trades) | 52.2% | 57.4% |
| Rebalances | 0 | 192 (102 buy / 90 sell) | 207 (113 buy / 94 sell) |
**The uncomfortable headline: over this exact 2-year window, simply buying
and holding PAXG beat both managed passes by roughly 27 points**, even
after the managed passes' real drawdown-reduction benefit (27.74% → 15.48%,
a genuine ~12-point improvement) is accounted for. Astro adds a modest
+0.7pp of P&L and +5.2pp of win rate over the no-astro pass in this window,
at the cost of ~1.9pp more drawdown and 15 more rebalances (more fee drag)
— a wash at best, not the standalone edge the old docstring implied.
This is exactly the question `compare_baselines.py` (below) is built to
keep asking on a rolling basis, not just as a one-time backtest: **did the
live bot beat just holding gold?** Publish the answer every week — including
when it's no.
## Single source of truth
Every published performance number now traces to `backtest_claims.py`,
populated directly from this re-run. Nothing else in the codebase should
hardcode a backtest number — import from `backtest_claims.py` instead.