mirror of
https://github.com/jaxperro/winning-wallet-finder.git
synced 2026-07-27 15:57:47 +00:00
copybot: per-niche FAK re-quote waits from measured crater-refill times
The flat 10s retry was calibrated to nothing; the tape now says craters
refill at very different speeds (research requote_timing, 775k crater
prints): crypto 94% within 4s, esports 83% within 10s, sports only 70% at
10s but 76% by 25s, geo/politics tails run minutes (price guard is the
protection there, not the retry). Waits move to FAK_RETRY_NICHE_DEFAULT
{crypto 4, esports 10, sports/geo/politics/other 25}, classified by the
validated research niche patterns (esports before sports so 'LoL: A vs B'
doesn't fall through on ' vs '). cfg fak_retry_niche_s overrides per key;
fak_retry_s stays the fallback (tennis: no measurement yet) and 0 still
disables the feature. Paper-parity: same map both bots. test t8 covers the
map, first-match classing, fallback, and config override.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+4
-2
@@ -41,8 +41,10 @@ push through.
|
||||
07-19 reconcile. **wwf-copybot** (paper $1k): same set, FAK-parity fills.
|
||||
Both on the audit-hardened build (locks, chain-gated sweep, boot-id
|
||||
single-writer guard, TLS'd user-ws — HANDOFF_ARCHIVE rev 16). 2026-07-20:
|
||||
FAK no-match OPENs get one 10s re-quote retry on both bots (`fak_retry_s`,
|
||||
paper-parity; misses from a second rejection tag "twice (re-quote retry)").
|
||||
FAK no-match OPENs get one re-quote retry on both bots, PER-NICHE waits
|
||||
from measured crater-refill times (crypto 4s / esports 10s / sports+slow
|
||||
25s — research/params/requote_timing.json; `fak_retry_niche_s` override,
|
||||
`fak_retry_s` fallback+kill-switch; second rejection tags "twice").
|
||||
- **wwf-recorder**: the FULL firehose (trades + order matches + comments
|
||||
+ crypto ticks, ~8M events/day, dual-socket ~99.9% capture, 25GB volume,
|
||||
NOTHING deleted until the Mac verifiably ingests it) → nightly →
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
"bankroll_pct": 0.04,
|
||||
"price_guard_abs": 0.05,
|
||||
"fak_retry_s": 10,
|
||||
"fak_retry_niche_s": {"crypto": 4, "esports": 10, "sports": 25,
|
||||
"geo": 25, "politics": 25, "other": 25},
|
||||
"taker_fee_rate": 0.03,
|
||||
"discord_webhook": "",
|
||||
"follow": {
|
||||
|
||||
+51
-5
@@ -243,6 +243,40 @@ FEED_PUSH_MIN_S = 120 # min seconds between feed git-pushes
|
||||
# with "taker_fee_rate" in config.json if that changes.
|
||||
TAKER_FEE_RATE = 0.03
|
||||
|
||||
# FAK re-quote retry, per market niche. Waits are the measured crater-refill
|
||||
# times (research/params/requote_timing.json, 775k crater prints, 2026-07-20):
|
||||
# crypto books refill <4s 94% of the time, esports 83% by 10s, sports needs
|
||||
# ~25s (70% at 10s -> 76% at 25s); geo/politics/other tails run minutes, so
|
||||
# 25s is the cap — beyond that the price guard is the protection, not the
|
||||
# retry. Patterns are the validated research/tape.py classifier, first match
|
||||
# wins (esports before sports: "LoL: A vs B" must not fall through to
|
||||
# sports on " vs "). Config: fak_retry_niche_s overrides per key;
|
||||
# fak_retry_s stays the fallback for unmatched niches and 0 disables the
|
||||
# whole feature.
|
||||
FAK_RETRY_NICHE_DEFAULT = {"crypto": 4.0, "esports": 10.0, "sports": 25.0,
|
||||
"geo": 25.0, "politics": 25.0, "other": 25.0}
|
||||
NICHE_PATTERNS = [
|
||||
("esports", ["lol:", "dota", "cs2", "csgo", "valorant", "esports",
|
||||
"bilibili", "map ", "game 1", "game 2", "game 3"]),
|
||||
("tennis", ["tennis", "atp", "wta", "wimbledon", "set winner"]),
|
||||
("sports", [" vs. ", " vs ", " @ ", "mlb", "nba", "nhl", "ufc",
|
||||
"world cup", "f1", "grand prix", "fifa"]),
|
||||
("crypto", ["bitcoin", "btc", "ethereum", "solana", "xrp", "doge",
|
||||
"price of", "up or down"]),
|
||||
("politics", ["election", "president", "senate", "governor", "mayor",
|
||||
"nominee", "impeach", "tariff", "fed ", "rate cut"]),
|
||||
("geo", ["iran", "israel", "russia", "ukraine", "china", "taiwan",
|
||||
"ceasefire", "strike", "nato"]),
|
||||
]
|
||||
|
||||
|
||||
def market_niche(title):
|
||||
t = (title or "").lower()
|
||||
for label, pats in NICHE_PATTERNS:
|
||||
if any(p in t for p in pats):
|
||||
return label
|
||||
return "other"
|
||||
|
||||
|
||||
def taker_fee(shares, price, rate):
|
||||
return shares * rate * price * (1.0 - price)
|
||||
@@ -894,8 +928,16 @@ class Copybot:
|
||||
engine.state["lag_recent"] = self._backfill_lag_recent()
|
||||
self.fee_rate = float(cfg.get("taker_fee_rate", TAKER_FEE_RATE))
|
||||
# FAK no-match re-quote retry wait (s); 0 disables (miss recorded at
|
||||
# the first rejection, pre-2026-07-20 behavior)
|
||||
# the first rejection, pre-2026-07-20 behavior). Per-niche waits from
|
||||
# the measured crater-refill times (see FAK_RETRY_NICHE_DEFAULT);
|
||||
# fak_retry_s is the fallback for niches without a measurement.
|
||||
self.fak_retry_s = float(cfg.get("fak_retry_s", 10))
|
||||
self.fak_retry_niche = {
|
||||
k: float(v) for k, v in {**FAK_RETRY_NICHE_DEFAULT,
|
||||
**(cfg.get("fak_retry_niche_s") or {})}.items()}
|
||||
|
||||
def _fak_wait(self, title):
|
||||
return self.fak_retry_niche.get(market_niche(title), self.fak_retry_s)
|
||||
|
||||
def _backfill_lag_recent(self, window_s=86400):
|
||||
"""[[ts, lag_s, slip], …] for fills in the last window_s, read from the
|
||||
@@ -1162,9 +1204,13 @@ class Copybot:
|
||||
rows instead of surfacing later as an untracked orphan; a second
|
||||
rejection records the miss inside _handle_their_buy, tagged
|
||||
'twice (re-quote retry)'. Installed on engine.on_fak_reject by
|
||||
main() when cfg fak_retry_s > 0 (default 10)."""
|
||||
main() when cfg fak_retry_s > 0. The wait is PER NICHE (_fak_wait):
|
||||
measured crater-refill times, crypto 4s / esports 10s / sports+slow
|
||||
books 25s (research requote_timing, 2026-07-20)."""
|
||||
wait = self._fak_wait(ctx["title"])
|
||||
|
||||
def run():
|
||||
time.sleep(self.fak_retry_s)
|
||||
time.sleep(wait)
|
||||
tok = ctx["token"]
|
||||
try:
|
||||
with self.lock:
|
||||
@@ -1188,8 +1234,8 @@ class Copybot:
|
||||
self.check_book()
|
||||
except Exception as e:
|
||||
log(f"re-quote retry error ({ctx['label'][:36]}): {e}")
|
||||
log(f"FAK no-match — re-quote retry in {self.fak_retry_s:.0f}s: "
|
||||
f"{ctx['label'][:48]}")
|
||||
log(f"FAK no-match — re-quote retry in {wait:.0f}s "
|
||||
f"({market_niche(ctx['title'])}): {ctx['label'][:48]}")
|
||||
threading.Thread(target=run, daemon=True).start()
|
||||
|
||||
def _ledger_buy_tokens(self):
|
||||
|
||||
@@ -159,6 +159,7 @@ def t7():
|
||||
bot.here = ""
|
||||
bot.check_book = lambda: None # network-touching, not under test
|
||||
copybot.book_depth = lambda t: None # _record_lag's book snapshot
|
||||
bot.fak_retry_niche = {} # force the scalar fallback
|
||||
bot.fak_retry_s = 0.05
|
||||
eng.on_fak_reject = bot.fak_requote_retry
|
||||
their_buy(eng) # reject -> schedules the retry
|
||||
@@ -173,6 +174,23 @@ def t7():
|
||||
assert not eng.state.get("missed"), eng.state["missed"]
|
||||
|
||||
|
||||
|
||||
@case("per-niche retry waits: measured map, first-match classing, fallback")
|
||||
def t8():
|
||||
eng = mkengine("fak")
|
||||
bot = copybot.Copybot(eng.cfg, eng, filt=None)
|
||||
assert bot._fak_wait("Ethereum above 1,900 on July 20, 12PM ET?") == 4.0
|
||||
assert bot._fak_wait("LoL: G2 Esports vs LYON - Game 2 Winner") == 10.0
|
||||
assert bot._fak_wait("Will Argentina win the 2026 FIFA World Cup?") == 25.0
|
||||
assert bot._fak_wait("Israel x Iran ceasefire continues through July 20?") == 25.0
|
||||
assert bot._fak_wait("Completely unclassifiable market") == 25.0 # other
|
||||
assert bot._fak_wait("Wimbledon: Alcaraz set winner") == bot.fak_retry_s # tennis: no measurement -> fallback
|
||||
eng.cfg["fak_retry_niche_s"] = {"crypto": 2}
|
||||
bot2 = copybot.Copybot(eng.cfg, eng, filt=None)
|
||||
assert bot2._fak_wait("Bitcoin above 63,400 on July 17, 3PM ET?") == 2.0
|
||||
|
||||
|
||||
|
||||
print()
|
||||
print("FAILURES:", fails or "none")
|
||||
sys.exit(1 if fails else 0)
|
||||
|
||||
Reference in New Issue
Block a user