From 8e431d6c774bf622c70a8af19c68a6ccb5d7b1dc Mon Sep 17 00:00:00 2001 From: jaxperro Date: Thu, 9 Jul 2026 14:39:45 -0400 Subject: [PATCH] =?UTF-8?q?engine:=20no=20silent=20exits=20after=20FOLLOW?= =?UTF-8?q?=20=E2=80=94=20thin-book=20and=20order-rejection=20record=20mis?= =?UTF-8?q?ses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Nine fills across both books were followed (tx in seen) and then died without a trace: _live_price None (no ask — the sharp is the maker on weekly scalars) and live ORDER FAILED both returned silently. A blocked or rejected OPEN is a missed bet; now recorded with its true reason. Allowance ruled out (max-uint on all three exchange contracts). Co-Authored-By: Claude Fable 5 --- copytrade.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/copytrade.py b/copytrade.py index c3fec774..ef1465cb 100644 --- a/copytrade.py +++ b/copytrade.py @@ -436,6 +436,14 @@ class CopyTrader: price = self._live_price(token, "buy") if price is None: + # thin/one-sided book — the sharp is often the MAKER here (weekly + # scalars especially), so there is no ask to lift when the copy + # arrives. This silent return hid 9 followed-but-unplaced fills + # across both books on 2026-07-09; a blocked OPEN is a missed bet. + if not is_add: + self.record_miss(wallet, token, cond, title, outcome, + their_price, self.stake_usd(wallet), + "no ask side on the book at copy time") return if not self._price_guard_ok(price, their_price): self.log(f"BUY {label} — skip (price {price:.3f} vs their " @@ -477,6 +485,9 @@ class CopyTrader: res = self.ex.buy(token, shares, price, {"title": title}) if not res["ok"]: self.log(f"{kind} {label} — ORDER FAILED: {res.get('resp')}") + if not is_add: # a rejected OPEN is a missed bet + self.record_miss(wallet, token, cond, title, outcome, price, + allowed, f"order rejected: {str(res.get('resp'))[:60]}") return spent = res["filled_shares"] * res["price"] self.state["spend"]["usd"] += spent