Files
trumpsignal-backend/scripts/sweep_moonshot.py
T
k 5d1bdc1ff2 chore: add $500 capital sweep scripts (conservative + moonshot)
scripts/sweep_500.py:
  Parameter grid for capital-preservation oriented configs.
  Risk filters: max DD <= 30%, max single loss <= 16% of capital.

scripts/sweep_moonshot.py:
  Aggressive grid for one-trade-hits-big strategy.
  Looser DD ceiling (50%), prioritizes biggest single-trade upside.

Both run on the local v4 dataset to inform initial subscription
parameter choices for live trading. Re-run after v5 accumulates
enough signals (~6 weeks) to recalibrate.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 16:07:46 +08:00

181 lines
6.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
Moonshot sweep: maximize SINGLE-TRADE upside, accept higher drawdown.
Strategy hypothesis:
- User does NOT care about monthly stability.
- User wants 1-2 trades a month that individually return 20-50%+ of capital.
- Acceptable trade-off: more losing months, occasional -30% drawdowns,
in exchange for fat-tail capture of the right signals.
Sim differences vs sweep_500:
- Higher leverage tier (up to 30×)
- Larger per-trade margin (% of capital)
- Higher conf floors (90, 95) — only the cleanest signals
- Wider TP grid (1% up to 5% to capture biggest moves)
- Tight SL (0.5% / 1% only — cut losers fast)
- Looser DD filter (allow up to 50% account drawdown)
- Reports BIGGEST winning trade explicitly
"""
import sqlite3
import statistics
from itertools import product
from pathlib import Path
DB = Path(__file__).resolve().parents[1] / "trumpsignal.db"
CAPITAL = 500.0
FEE_BPS_RT = 0.0009
def fetch_signals(conf_floor: int):
con = sqlite3.connect(DB)
con.row_factory = sqlite3.Row
rows = con.execute("""
SELECT id, signal, ai_confidence, price_impact_m1h
FROM posts
WHERE signal IN ('buy', 'short')
AND price_at_post IS NOT NULL
AND price_impact_m1h IS NOT NULL
AND ai_confidence >= ?
ORDER BY published_at
""", (conf_floor,)).fetchall()
con.close()
return [dict(r) for r in rows]
def simulate(signals, margin: float, leverage: int, tp_pct: float, sl_pct: float):
"""Return list of per-trade $ PnL."""
notional = margin * leverage
pnls: list[float] = []
for s in signals:
peak = s["price_impact_m1h"]
if peak >= tp_pct:
gross = tp_pct
elif peak < 0:
gross = -sl_pct
else:
gross = peak / 2
net_pct = gross / 100 - FEE_BPS_RT
pnls.append(notional * net_pct)
return pnls
def metrics(pnls):
n = len(pnls)
if n == 0:
return None
total = sum(pnls)
wins = sum(1 for p in pnls if p > 0)
biggest_win = max(pnls)
biggest_loss = min(pnls)
equity, peak, maxdd = CAPITAL, CAPITAL, 0.0
for p in pnls:
equity += p
peak = max(peak, equity)
maxdd = max(maxdd, peak - equity)
return {
"n": n,
"wins": wins,
"win_rate": round(wins/n*100, 1),
"total": round(total, 2),
"biggest_win": round(biggest_win, 2),
"biggest_loss": round(biggest_loss, 2),
"max_dd": round(maxdd, 2),
"max_dd_pct": round(maxdd/CAPITAL*100, 1),
"roi_pct": round(total/CAPITAL*100, 1),
# "best-trade-as-%-of-capital" — the moonshot metric
"best_trade_pct": round(biggest_win/CAPITAL*100, 1),
}
def main():
print("$500 MOONSHOT SWEEP — maximize single-trade upside")
print("=" * 100)
# Aggressive grid
confs = [80, 85, 90, 95]
margins = [50, 100, 150, 200]
levs = [10, 15, 20, 25, 30]
tps = [1.0, 1.5, 2.0, 3.0, 5.0]
sls = [0.5, 1.0, 1.5]
results = []
for conf in confs:
sigs = fetch_signals(conf)
if not sigs:
continue
for margin, lev, tp, sl in product(margins, levs, tps, sls):
# Notional cap: don't exceed 12× capital total exposure
if margin * lev > CAPITAL * 12:
continue
pnls = simulate(sigs, margin, lev, tp, sl)
m = metrics(pnls)
m.update({
"conf": conf, "margin": margin, "lev": lev,
"tp": tp, "sl": sl,
"max_loss_per_trade": round(margin * lev * (sl/100 + FEE_BPS_RT), 2),
})
results.append(m)
# Soft filter: at least 5 trades, profitable, drawdown <50% (acceptable for moonshot)
candidates = [r for r in results
if r["n"] >= 5 and r["total"] > 0 and r["max_dd_pct"] <= 50]
print(f"\n{len(candidates)} viable combos (n>=5, profitable, DD<=50%)")
print()
# ── 1. Highest single-trade upside ─────────────────────────────
print("=" * 100)
print("TOP 10 — BIGGEST SINGLE WINNING TRADE (the 'one trade hits big' goal)")
print("=" * 100)
print(f"{'conf':>4} {'margin':>6} {'lev':>3} {'TP%':>4} {'SL%':>4} "
f"{'n':>3} {'win%':>5} {'best_win$':>9} {'best%cap':>9} "
f"{'maxLoss$':>8} {'total$':>8} {'DD%':>5}")
for r in sorted(candidates, key=lambda x: -x["biggest_win"])[:10]:
print(f"{r['conf']:>4} ${r['margin']:>5} {r['lev']:>3}× "
f"{r['tp']:>4.1f} {r['sl']:>4.1f} "
f"{r['n']:>3} {r['win_rate']:>4.1f}% "
f"${r['biggest_win']:>+7.2f} {r['best_trade_pct']:>+7.1f}% "
f"${r['max_loss_per_trade']:>6.2f} ${r['total']:>+6.2f} "
f"{r['max_dd_pct']:>4.1f}%")
# ── 2. Best total ROI accepting bigger drawdown ────────────────
print()
print("=" * 100)
print("TOP 10 — TOTAL ROI (any drawdown ≤ 50%)")
print("=" * 100)
print(f"{'conf':>4} {'margin':>6} {'lev':>3} {'TP%':>4} {'SL%':>4} "
f"{'n':>3} {'win%':>5} {'total$':>8} {'ROI%':>6} "
f"{'maxLoss$':>8} {'maxDD%':>6} {'best%':>6}")
for r in sorted(candidates, key=lambda x: -x["roi_pct"])[:10]:
print(f"{r['conf']:>4} ${r['margin']:>5} {r['lev']:>3}× "
f"{r['tp']:>4.1f} {r['sl']:>4.1f} "
f"{r['n']:>3} {r['win_rate']:>4.1f}% "
f"${r['total']:>+6.2f} {r['roi_pct']:>+5.1f}% "
f"${r['max_loss_per_trade']:>6.2f} {r['max_dd_pct']:>5.1f}% "
f"{r['best_trade_pct']:>+5.1f}%")
# ── 3. The "Black Swan" candidate — biggest in absolute $ terms ─
print()
print("=" * 100)
print("DATA REALITY CHECK — biggest |move| observed across all signals")
print("=" * 100)
con = sqlite3.connect(DB)
rows = con.execute("""
SELECT id, signal, ai_confidence, price_impact_m1h
FROM posts WHERE signal IN ('buy','short')
AND price_impact_m1h IS NOT NULL
ORDER BY ABS(price_impact_m1h) DESC LIMIT 5
""").fetchall()
con.close()
print(f" {'rank':>4} {'id':>5} {'sig':>5} {'conf':>4} {'1h move':>10}")
for i, r in enumerate(rows, 1):
print(f" {i:>4} {r[0]:>5} {r[1]:>5} {r[2]:>4} {r[3]:>+9.3f}%")
print()
print("→ With $200 margin × 30× = $6000 notional, the 2.36% best move")
print(f" would have netted: ${6000*0.0236-6000*0.0009:.2f} on a single trade")
print(f" = {(6000*0.0236-6000*0.0009)/CAPITAL*100:.1f}% of $500 capital from ONE trade")
if __name__ == "__main__":
main()