mirror of
https://github.com/jaxperro/winning-wallet-finder.git
synced 2026-08-07 05:07:47 +00:00
forward: chain-overlay payouts — pendings were hiding the losses
THE SCORER BUG (found 2026-07-22 by the surge paper book divergence): tape-resolution timing is win-biased. When our side LOSES, the winning sibling keeps trading at 99c until close, the sibling-veto keeps the market 'alive', and the loss sits in the ignored pending bucket — while wins tape-resolve within hours and score. Jul-21 audit: tape-resolved fills 81% hit (+$46/fill); chain-resolving the 329 'pending' fills: 26% hit, -$49.61/fill; combined truth 53% ≈ the paper book's 57.5%. The paper harness was the honest instrument; every ledger arm was flattered. payouts_for(): tape proxy first, CTF chain truth for the remainder (payouts.py cache — immutable, so nightly incremental cost is small); refunds (0.5) now booked as scratches. Applied to flow, controls, and oracle (sub5c inherits via score_flow). Ledger recompute follows; #16 verdict evaluates corrected numbers only. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+69
-26
@@ -36,6 +36,38 @@ def day_bounds(d):
|
|||||||
return lo, lo + 86400
|
return lo, lo + 86400
|
||||||
|
|
||||||
|
|
||||||
|
def payouts_for(db, assets):
|
||||||
|
"""asset -> payout via tape proxy FIRST, then CTF chain truth for the
|
||||||
|
rest. THE 2026-07-22 SCORER BUG: 'pending' was treated as ignorable,
|
||||||
|
but tape-resolution timing is win-biased — a LOSS keeps its winning
|
||||||
|
sibling trading (sibling-veto holds the market open), so losses hid in
|
||||||
|
pending while wins scored. Jul-21 audit: tape-resolved fills hit 81%;
|
||||||
|
chain-resolving the 'pending' bucket hit 26% (n=329) — combined 53%.
|
||||||
|
The surge paper book (chain-graded from day one) was right; this
|
||||||
|
scorer was flattering every arm. Chain overlay is now mandatory."""
|
||||||
|
out, missing = {}, []
|
||||||
|
for a in set(assets):
|
||||||
|
r = db.execute("SELECT payout::DOUBLE FROM res_tok WHERE asset=?",
|
||||||
|
[a]).fetchone()
|
||||||
|
if r:
|
||||||
|
out[a] = r[0]
|
||||||
|
else:
|
||||||
|
missing.append(a)
|
||||||
|
conds = {}
|
||||||
|
for a in missing:
|
||||||
|
c = db.execute("SELECT any_value(cond) FROM trades WHERE asset=?",
|
||||||
|
[a]).fetchone()[0]
|
||||||
|
if c:
|
||||||
|
conds[a] = c
|
||||||
|
if conds:
|
||||||
|
tr = tape.chain_overlay([(c, a) for a, c in conds.items()])
|
||||||
|
for a, c in conds.items():
|
||||||
|
v = tr.get((c, a))
|
||||||
|
if v is not None:
|
||||||
|
out[a] = v # 1.0 / 0.0 / 0.5 (refund)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def score_flow(db, fz, d, hold_s):
|
def score_flow(db, fz, d, hold_s):
|
||||||
lo, hi = day_bounds(d)
|
lo, hi = day_bounds(d)
|
||||||
t_max = db.execute("SELECT max(ts) FROM trades").fetchone()[0]
|
t_max = db.execute("SELECT max(ts) FROM trades").fetchone()[0]
|
||||||
@@ -44,21 +76,24 @@ def score_flow(db, fz, d, hold_s):
|
|||||||
tape.build_resolved(db)
|
tape.build_resolved(db)
|
||||||
trig = sf.signals(db, S, lo, hi, fz["window_s"], fz["flow_usd"])
|
trig = sf.signals(db, S, lo, hi, fz["window_s"], fz["flow_usd"])
|
||||||
row = {"triggers": len(trig), "set_size": len(S)}
|
row = {"triggers": len(trig), "set_size": len(S)}
|
||||||
|
pays = payouts_for(db, [t["asset"] for t in trig])
|
||||||
for mode in ("first", "worst"):
|
for mode in ("first", "worst"):
|
||||||
s = simmod.Sim(db, lag_s=simmod.LAG_P50, hold_s=hold_s, fill=mode)
|
s = simmod.Sim(db, lag_s=simmod.LAG_P50, hold_s=hold_s, fill=mode)
|
||||||
agg = dict(fills=0, misses=0, pending=0, pnl=0.0, wins=0)
|
agg = dict(fills=0, misses=0, pending=0, refunds=0, pnl=0.0, wins=0)
|
||||||
for t in trig:
|
for t in trig:
|
||||||
pay = db.execute("SELECT payout::DOUBLE FROM res_tok WHERE asset=?",
|
pay = pays.get(t["asset"])
|
||||||
[t["asset"]]).fetchone()
|
|
||||||
r = s.try_buy(t["asset"], t["ts"], t["p_ref"], stake_usd=sf.STAKE)
|
r = s.try_buy(t["asset"], t["ts"], t["p_ref"], stake_usd=sf.STAKE)
|
||||||
if not r["filled"]:
|
if not r["filled"]:
|
||||||
agg["misses"] += 1
|
agg["misses"] += 1
|
||||||
elif pay is None:
|
elif pay is None: # truly unresolved (chain included)
|
||||||
agg["pending"] += 1
|
agg["pending"] += 1
|
||||||
|
elif pay == 0.5:
|
||||||
|
agg["refunds"] += 1
|
||||||
|
agg["pnl"] += r["shares"] * 0.5 - r["cost"] - r["fee"]
|
||||||
else:
|
else:
|
||||||
agg["fills"] += 1
|
agg["fills"] += 1
|
||||||
agg["pnl"] += r["shares"] * (pay[0] - r["price"]) - r["fee"]
|
agg["pnl"] += r["shares"] * (pay - r["price"]) - r["fee"]
|
||||||
agg["wins"] += pay[0] == 1.0
|
agg["wins"] += pay == 1.0
|
||||||
agg["pnl"] = round(agg["pnl"], 2)
|
agg["pnl"] = round(agg["pnl"], 2)
|
||||||
if agg["fills"]:
|
if agg["fills"]:
|
||||||
agg["ev_per_fill"] = round(agg["pnl"] / agg["fills"], 2)
|
agg["ev_per_fill"] = round(agg["pnl"] / agg["fills"], 2)
|
||||||
@@ -68,16 +103,16 @@ def score_flow(db, fz, d, hold_s):
|
|||||||
for seed in CONTROL_SEEDS:
|
for seed in CONTROL_SEEDS:
|
||||||
C = sf.matched_random_set(db, lo, fz["top_n"], seed)
|
C = sf.matched_random_set(db, lo, fz["top_n"], seed)
|
||||||
ctrig = sf.signals(db, C, lo, hi, fz["window_s"], fz["flow_usd"])
|
ctrig = sf.signals(db, C, lo, hi, fz["window_s"], fz["flow_usd"])
|
||||||
|
cpays = payouts_for(db, [t["asset"] for t in ctrig])
|
||||||
s = simmod.Sim(db, lag_s=simmod.LAG_P50, hold_s=hold_s, fill="worst")
|
s = simmod.Sim(db, lag_s=simmod.LAG_P50, hold_s=hold_s, fill="worst")
|
||||||
fills = 0
|
fills = 0
|
||||||
pnl = 0.0
|
pnl = 0.0
|
||||||
for t in ctrig:
|
for t in ctrig:
|
||||||
pay = db.execute("SELECT payout::DOUBLE FROM res_tok WHERE asset=?",
|
pay = cpays.get(t["asset"])
|
||||||
[t["asset"]]).fetchone()
|
|
||||||
r = s.try_buy(t["asset"], t["ts"], t["p_ref"], stake_usd=sf.STAKE)
|
r = s.try_buy(t["asset"], t["ts"], t["p_ref"], stake_usd=sf.STAKE)
|
||||||
if r["filled"] and pay is not None:
|
if r["filled"] and pay is not None and pay != 0.5:
|
||||||
fills += 1
|
fills += 1
|
||||||
pnl += r["shares"] * (pay[0] - r["price"]) - r["fee"]
|
pnl += r["shares"] * (pay - r["price"]) - r["fee"]
|
||||||
ctl.append({"seed": seed, "fills": fills, "pnl": round(pnl, 2)})
|
ctl.append({"seed": seed, "fills": fills, "pnl": round(pnl, 2)})
|
||||||
row["controls_worst"] = ctl
|
row["controls_worst"] = ctl
|
||||||
return row
|
return row
|
||||||
@@ -94,10 +129,8 @@ def score_oracle(db, P, d, hold_s):
|
|||||||
outcomes = so.outcome_map(db)
|
outcomes = so.outcome_map(db)
|
||||||
tape.build_resolved(db)
|
tape.build_resolved(db)
|
||||||
uni = so.crypto_universe(db, outcomes, series)
|
uni = so.crypto_universe(db, outcomes, series)
|
||||||
payout = {a: p for a, p in db.execute(
|
|
||||||
"SELECT asset, payout::DOUBLE FROM res_tok").fetchall()}
|
|
||||||
sim = simmod.Sim(db, hold_s=hold_s)
|
sim = simmod.Sim(db, hold_s=hold_s)
|
||||||
row = {}
|
evs = [] # (asset, edge, sim result) — score after
|
||||||
for u in uni:
|
for u in uni:
|
||||||
prints = db.execute("""SELECT ts, price FROM trades WHERE asset=?
|
prints = db.execute("""SELECT ts, price FROM trades WHERE asset=?
|
||||||
AND ts > ? AND ts <= ? ORDER BY ts""", [u["asset"], lo, hi]).fetchall()
|
AND ts > ? AND ts <= ? ORDER BY ts""", [u["asset"], lo, hi]).fetchall()
|
||||||
@@ -113,19 +146,29 @@ def score_oracle(db, P, d, hold_s):
|
|||||||
if edge < min(so.EDGE_GRID):
|
if edge < min(so.EDGE_GRID):
|
||||||
continue
|
continue
|
||||||
last_ev = ts
|
last_ev = ts
|
||||||
r = sim.try_buy(u["asset"], ts, float(px), stake_usd=so.STAKE)
|
evs.append((u["asset"], edge,
|
||||||
for E in so.EDGE_GRID:
|
sim.try_buy(u["asset"], ts, float(px),
|
||||||
if edge < E:
|
stake_usd=so.STAKE)))
|
||||||
continue
|
# chain-overlay payouts (same 2026-07-22 scorer fix as score_flow)
|
||||||
g = row.setdefault(str(E), {"events": 0, "fills": 0,
|
pays = payouts_for(db, [a for a, _, r in evs if r["filled"]])
|
||||||
"pending": 0, "pnl": 0.0, "wins": 0})
|
row = {}
|
||||||
g["events"] += 1
|
for asset, edge, r in evs:
|
||||||
if not r["filled"]:
|
for E in so.EDGE_GRID:
|
||||||
continue
|
if edge < E:
|
||||||
pay = payout.get(u["asset"])
|
continue
|
||||||
if pay is None:
|
g = row.setdefault(str(E), {"events": 0, "fills": 0,
|
||||||
g["pending"] += 1
|
"pending": 0, "refunds": 0,
|
||||||
continue
|
"pnl": 0.0, "wins": 0})
|
||||||
|
g["events"] += 1
|
||||||
|
if not r["filled"]:
|
||||||
|
continue
|
||||||
|
pay = pays.get(asset)
|
||||||
|
if pay is None:
|
||||||
|
g["pending"] += 1
|
||||||
|
elif pay == 0.5:
|
||||||
|
g["refunds"] += 1
|
||||||
|
g["pnl"] += r["shares"] * 0.5 - r["cost"] - r["fee"]
|
||||||
|
else:
|
||||||
g["fills"] += 1
|
g["fills"] += 1
|
||||||
g["pnl"] += r["shares"] * (pay - r["price"]) - r["fee"]
|
g["pnl"] += r["shares"] * (pay - r["price"]) - r["fee"]
|
||||||
g["wins"] += pay == 1.0
|
g["wins"] += pay == 1.0
|
||||||
|
|||||||
Reference in New Issue
Block a user