research: Study C FREEZE — maker inventory-lean pre-registration (follow arm verdict; fade failed its concentration gate)

score_lean wired into the nightly (walk-forward as-of screening, frozen
trigger, chain truth); params/study_lean.json frozen; forward window =
ledger rows dated after this commit. Fade $2k+ arm excluded by the
pre-declared gate (top event 32%, tail net-negative) — tracked
report-only. Follow $150-500: robust across 869 events (top 14%).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
jaxperro
2026-07-23 15:49:49 -04:00
parent 829e7634dd
commit 052eda04d1
4 changed files with 129 additions and 35 deletions
+60
View File
@@ -180,6 +180,56 @@ def score_oracle(db, P, d, hold_s):
return row
def score_lean(db, d):
"""Study C (maker inventory-lean, pre-registered): walk-forward day row.
Screen as-of day start (maker_lean.screen_asof — tape strictly before
the day), frozen trigger (maker_lean.day_leans), chain truth via
payouts_for. Arms: follow_small ($150-500) · fade_whale ($2k+) · mid
bucket report-only. Scored at last-print entry (stated optimism — a
PASS graduates to a real-execution paper arm, never to money)."""
import maker_lean as ml
lo, hi = day_bounds(d)
t_max = db.execute(
"SELECT max(ts) FROM aux WHERE type='orders_matched'").fetchone()[0]
hi = min(hi, t_max or 0)
if hi <= lo:
return {"skipped": "no maker-stream coverage"}
tape.build_resolved(db)
sharps = ml.screen_asof(db, lo)
if not sharps:
return {"skipped": "no screened wallets as-of day"}
leans = ml.day_leans(db, lo, hi, sharps)
pays = payouts_for(db, [t["a"] for t in leans])
row = {"screened": len(sharps), "leans": len(leans)}
arms = {"follow_small": ("follow", lambda u: u < 500),
"mid_report": ("follow", lambda u: 500 <= u < 2000),
"fade_whale": ("fade", lambda u: u >= 2000)}
for name, (direction, sel) in arms.items():
n = pend = wins = 0
pnl = 0.0
for t in leans:
if not sel(t["lean_usd"]):
continue
p = pays.get(t["a"])
if p is None:
pend += 1
continue
if p == 0.5:
continue
lean_pay = p if t["side"] > 0 else 1 - p
px, pay = ((t["lean_px"], lean_pay) if direction == "follow"
else (1 - t["lean_px"], 1 - lean_pay))
if not (0.05 <= px <= 0.95):
continue
n += 1
pnl += 100.0 / px * (pay - px)
wins += pay == 1.0
row[name] = {"n": n, "pending": pend, "pnl": round(pnl, 2),
"ev_per_lean": round(pnl / n, 2) if n else None,
"hit": round(wins / n, 3) if n else None}
return row
def main():
db = tape.connect()
cal = json.load(open(os.path.join(HERE, "params", "sim_calibration.json")))
@@ -248,6 +298,16 @@ def main():
print(f"sub5c {d}: trig {r3['triggers']} "
f"worst {r3['worst'].get('ev_per_fill')} "
f"({r3['worst']['fills']} fills, {r3['worst']['pending']} pend)")
r5 = score_lean(db, d)
fh.write(json.dumps({"study": "lean", "day": d,
"computed_at": now, **r5},
default=float) + "\n")
print(f"lean {d}: " + (r5.get("skipped") or
f"{r5['leans']} leans · follow_small "
f"{r5['follow_small'].get('ev_per_lean')} "
f"({r5['follow_small']['n']}n) · fade_whale "
f"{r5['fade_whale'].get('ev_per_lean')} "
f"({r5['fade_whale']['n']}n)"))
if __name__ == "__main__":
+47 -35
View File
@@ -17,6 +17,7 @@ FROZEN v0 params (declared before the run, not tuned after):
price lean-side last print in [0.05, 0.95] at trigger
score $100 at trigger print -> chain payout; follow-EV and fade-EV
Kill bar: BOTH directions EV <= 0 at n>=100 leans."""
import os
import sys
import time
@@ -63,6 +64,43 @@ def screen_asof(db, t_cut):
return out
def day_leans(db, lo, hi, sharps):
"""First lean crossings for screened wallets in [lo,hi) — the frozen
trigger (used by the exploration AND forward.py's nightly scoring)."""
rows = db.execute("""
SELECT lower(json_extract_string(payload,'$.proxyWallet')) w,
json_extract_string(payload,'$.asset') a,
json_extract_string(payload,'$.side') s,
cast(json_extract(payload,'$.price') AS DOUBLE) p,
cast(json_extract(payload,'$.size') AS DOUBLE) z, ts
FROM aux WHERE type='orders_matched' AND ts >= ? AND ts < ?
ORDER BY ts""", [lo, hi]).fetchall()
book, fired, out = {}, set(), []
for w, a, s_, p, z, ts in rows:
if w not in sharps or (w, a) in fired:
continue
st = book.setdefault((w, a), [0.0, 0.0])
st[0] += z if s_ == "BUY" else -z
st[1] += z
net, gross = st
if gross < 1e-9:
continue
px = db.execute("""SELECT price FROM trades WHERE asset=?
AND ts<=? ORDER BY ts DESC LIMIT 1""", [a, ts]).fetchone()
if px is None:
continue
px = float(px[0])
lean_px = px if net > 0 else 1 - px
if (abs(net) * px >= LEAN_USD and abs(net) / gross >= NET_GROSS
and BAND[0] <= lean_px <= BAND[1]):
fired.add((w, a))
out.append({"w": w, "a": a, "ts": ts,
"side": 1 if net > 0 else -1,
"lean_usd": abs(net) * px,
"px": px, "lean_px": lean_px})
return out
def main():
db = tape.connect()
t_lo, t_hi = db.execute(
@@ -79,43 +117,17 @@ def main():
if not sharps:
print(f"{d_str}: 0 screened wallets", flush=True)
continue
rows = db.execute("""
SELECT lower(json_extract_string(payload,'$.proxyWallet')) w,
json_extract_string(payload,'$.asset') a,
json_extract_string(payload,'$.side') s,
cast(json_extract(payload,'$.price') AS DOUBLE) p,
cast(json_extract(payload,'$.size') AS DOUBLE) z, ts
FROM aux WHERE type='orders_matched' AND ts >= ? AND ts < ?
ORDER BY ts""", [lo, hi]).fetchall()
book = {} # (w,a) -> [net, gross, vwap$]
fired = set()
n_day = 0
for w, a, s, p, z, ts in rows:
if w not in sharps or (w, a) in fired:
continue
st = book.setdefault((w, a), [0.0, 0.0])
st[0] += z if s == "BUY" else -z
st[1] += z
net, gross = st
if gross < 1e-9:
continue
px = db.execute("""SELECT price FROM trades WHERE asset=?
AND ts<=? ORDER BY ts DESC LIMIT 1""", [a, ts]).fetchone()
if px is None:
continue
px = float(px[0])
lean_px = px if net > 0 else 1 - px # lean-side price
if (abs(net) * px >= LEAN_USD
and abs(net) / gross >= NET_GROSS
and BAND[0] <= lean_px <= BAND[1]):
fired.add((w, a))
n_day += 1
triggers.append({"w": w, "a": a, "ts": ts, "day": d_str,
"side": 1 if net > 0 else -1,
"lean_usd": abs(net) * px,
"px": px, "lean_px": lean_px})
found = day_leans(db, lo, hi, sharps)
for t in found:
t["day"] = d_str
triggers.extend(found)
n_day = len(found)
print(f"{d_str}: {len(sharps)} screened · {n_day} leans", flush=True)
print(f"total leans: {len(triggers)}", flush=True)
import json as _json
_json.dump(triggers, open(os.path.join(
os.path.dirname(os.path.abspath(__file__)),
".maker_lean_triggers.json"), "w"))
pays = fwd.payouts_for(db, [t["a"] for t in triggers])
graded = [(t, pays.get(t["a"])) for t in triggers]
graded = [(t, p) for t, p in graded if p is not None and p != 0.5]
+21
View File
@@ -0,0 +1,21 @@
{
"frozen_at": "2026-07-23 21:55 UTC",
"study": "C — maker inventory-lean (follow absorbed flow)",
"screen": {"source": "orders_matched maker fills, as-of day start (strictly prior tape)",
"min_z": 2.5, "min_bets": 6, "pnl_positive": true},
"trigger": {"lean_usd_min": 150.0, "net_gross_min": 0.6,
"first_crossing_per_wallet_asset_day": true,
"lean_px_band": [0.05, 0.95]},
"arms": {
"follow_small": {"role": "VERDICT", "range_usd": [150, 500], "direction": "follow",
"pass": "pooled forward EV >= +$2/lean AND hit >= 0.56 at n >= 1500 across >= 5 forward days",
"kill": "pooled forward EV <= 0 at n >= 1000"},
"mid_report": {"role": "report-only", "range_usd": [500, 2000], "direction": "follow"},
"fade_whale": {"role": "report-only — FAILED pre-declared concentration gate 2026-07-23",
"range_usd": [2000, null], "direction": "fade",
"gate_result": "top-event share 32% (>30% line); top-5 events +$7,799 vs +$5,911 total (tail net-negative); 87/224 events positive"}
},
"scoring": "last-print entry (STATED OPTIMISM) -> chain truth via payouts_for; nightly rows study='lean' in forward_ledger.jsonl (forward.score_lean)",
"graduation": "PASS graduates to a real-execution paper arm (honest instrument), never directly to money",
"exploration": "research/maker_lean.py walk-forward 07-21..23: follow_small +$2.90-4.39/lean, 59% hit, positive all 3 days; concentration follow 14% top-event / 869 events"
}