mirror of
https://github.com/jaxperro/winning-wallet-finder.git
synced 2026-07-27 15:57:47 +00:00
profit ratchet: stakes pin at $250, surplus swept to a banked reserve
Once working equity exceeds stake_cap/pct ($6,250 at 4%), surplus cash sweeps to state["reserve"]/portfolio reserve - banked, never bet, immune to drawdown - keeping stakes at the $250 level where marketable fills sit inside typical book depth. Feed/summary gain reserve; realized = cash+exposure+reserve-bank. June backfill: equity $15,684 (+1468%), $9,185 banked, next stake pinned $250. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+24
-6
@@ -54,6 +54,10 @@ DEFAULT_CONFIG = {
|
||||
"bankroll_pct": 0.02, # fraction of CURRENT equity per new entry
|
||||
# (compounds up and down; falls back to a flat
|
||||
# fraction of bankroll_usd when cash isn't tracked)
|
||||
"stake_cap_usd": 0, # >0: pin stakes at this size once the book grows
|
||||
# past cap/bankroll_pct — surplus cash is SWEPT to
|
||||
# state["reserve"], a banked pot that never bets
|
||||
# (profit ratchet + keeps fills inside book depth)
|
||||
"price_guard_pct": 0.05, # skip if price moved >5% from their fill
|
||||
"risk": {
|
||||
"max_trade_usd": 50.0, # hard ceiling on any single copy
|
||||
@@ -264,20 +268,34 @@ class CopyTrader:
|
||||
DD_FACTOR = 0.5 # …bet half size until equity recovers
|
||||
|
||||
def stake_usd(self):
|
||||
"""Next bet size = bankroll_pct × current equity (cash + open cost basis),
|
||||
so stakes compound with the book in both directions; halved while in a
|
||||
>20% drawdown from the high-water mark. Falls back to the flat static
|
||||
stake when cash isn't tracked (legacy poll CLI)."""
|
||||
"""Next bet size = bankroll_pct × current WORKING equity (cash + open cost
|
||||
basis), so stakes compound with the book in both directions; halved while
|
||||
in a >20% drawdown from the high-water mark. Falls back to the flat static
|
||||
stake when cash isn't tracked (legacy poll CLI).
|
||||
|
||||
stake_cap_usd (profit ratchet): once working equity exceeds
|
||||
cap/bankroll_pct — the level where stakes hit the cap — the surplus CASH
|
||||
is swept into state["reserve"]: banked, never bet, immune to drawdowns.
|
||||
Stakes stay pinned ~at the cap, where marketable fills are still inside
|
||||
typical book depth."""
|
||||
cash = self.state.get("cash")
|
||||
if cash is None:
|
||||
return self.cfg["bankroll_usd"] * self.cfg["bankroll_pct"]
|
||||
frac = self.cfg["bankroll_pct"]
|
||||
cap = self.cfg.get("stake_cap_usd") or 0
|
||||
eq = cash + self.open_exposure()
|
||||
if cap and frac > 0 and eq > cap / frac:
|
||||
sweep = min(cash, eq - cap / frac)
|
||||
if sweep > 0:
|
||||
self.state["cash"] = cash = cash - sweep
|
||||
self.state["reserve"] = self.state.get("reserve", 0.0) + sweep
|
||||
eq -= sweep
|
||||
hwm = max(self.state.get("hwm", 0.0), eq)
|
||||
self.state["hwm"] = hwm
|
||||
frac = self.cfg["bankroll_pct"]
|
||||
if eq < self.DD_THRESHOLD * hwm:
|
||||
frac *= self.DD_FACTOR
|
||||
return frac * eq
|
||||
stake = frac * eq
|
||||
return min(stake, cap) if cap else stake
|
||||
|
||||
def record_miss(self, wallet, token, cond, title, outcome, price, want, reason):
|
||||
"""A bet the strategy WOULD have copied but the book couldn't take —
|
||||
|
||||
+8
-4
@@ -407,7 +407,9 @@ class Copybot:
|
||||
"event_cap": self.engine.risk.get("max_per_event"),
|
||||
"hwm": round(st.get("hwm", 0.0), 2),
|
||||
"cash": round(cash, 2), "deployed": round(exp, 2),
|
||||
"realized": round(cash + exp - bank, 2), "open_count": len(mp),
|
||||
"reserve": round(st.get("reserve", 0.0), 2), # banked profit, never bet
|
||||
"realized": round(cash + exp + st.get("reserve", 0.0) - bank, 2),
|
||||
"open_count": len(mp),
|
||||
"fees_paid": round(st.get("fees_paid", 0.0), 2),
|
||||
"fee_rate": self.fee_rate,
|
||||
"lag": {"n": lag.get("n", 0),
|
||||
@@ -504,15 +506,17 @@ class Copybot:
|
||||
stake = self.engine.stake_usd() # dynamic: pct of current equity
|
||||
exp = self.engine.open_exposure()
|
||||
cash = self.engine.state.get("cash", bank)
|
||||
realized = cash + exp - bank # see _drain_fills / settle_resolved
|
||||
reserve = self.engine.state.get("reserve", 0.0)
|
||||
realized = cash + exp + reserve - bank # see _drain_fills / settle_resolved
|
||||
n = len(self.engine.state["my_pos"])
|
||||
lag = self.engine.state.get("lag", {})
|
||||
lagstr = ""
|
||||
if lag.get("n"):
|
||||
lagstr = (f" · {lag['n']} copies avg lag {lag['sum_s']/lag['n']:.0f}s "
|
||||
f"slip {lag['sum_slip_pct']/lag['n']:+.1%}")
|
||||
log(f"[{cycle}] open {n} · deployed ${exp:,.0f} · free ${cash:,.0f}/${bank:,.0f} "
|
||||
f"· realized ${realized:+,.2f}{lagstr}"
|
||||
bankstr = f" · banked ${reserve:,.0f}" if reserve else ""
|
||||
log(f"[{cycle}] open {n} · deployed ${exp:,.0f} · free ${cash:,.0f}/${bank:,.0f}"
|
||||
f"{bankstr} · realized ${realized:+,.2f}{lagstr}"
|
||||
+ (f" · CAN'T OPEN (free < ${stake:,.0f} stake — bets missed)"
|
||||
if cash < stake else ""))
|
||||
|
||||
|
||||
@@ -55,5 +55,6 @@
|
||||
"max_price": 0.99,
|
||||
"min_order_usd": 5.0,
|
||||
"max_per_event": 0
|
||||
}
|
||||
},
|
||||
"stake_cap_usd": 250.0
|
||||
}
|
||||
+1
-1
File diff suppressed because one or more lines are too long
+21
-9
@@ -47,7 +47,10 @@ GAMMA = "https://gamma-api.polymarket.com"
|
||||
# event (a game's markets settle together — one correlated bet, not N diversified
|
||||
# ones); 0 = off, mirror every conviction trade.
|
||||
PCT = 0.04
|
||||
STAKE_MIN, STAKE_CAP = 5.0, float("inf") # uncapped — 4% of equity rides fully
|
||||
# stakes pin at STAKE_CAP (where marketable fills still sit inside typical book
|
||||
# depth); once working equity exceeds STAKE_CAP/PCT, surplus cash is SWEPT into
|
||||
# a banked reserve — a profit ratchet that never bets and can't be drawn down.
|
||||
STAKE_MIN, STAKE_CAP = 5.0, 250.0
|
||||
EVENT_CAP = 0
|
||||
DD_THRESHOLD, DD_FACTOR = 0.80, 0.5
|
||||
# skip entries above this price. High-price favorites win pennies and lose
|
||||
@@ -207,6 +210,7 @@ def main():
|
||||
fees_paid = 0.0
|
||||
hwm = BANK
|
||||
capped = 0
|
||||
reserve = 0.0
|
||||
held = [] # (free_t, cost, payoff) cost = stake + entry fee; payoff paid at free_t
|
||||
perW = {w["wallet"]: {"name": w["name"], "wallet": w["wallet"], "bets": 0,
|
||||
"won": 0, "lost": 0,
|
||||
@@ -214,9 +218,15 @@ def main():
|
||||
resolved, current, missed = [], [], []
|
||||
|
||||
def cur_stake():
|
||||
"""PCT of current equity, drawdown-braked, clamped — the copybot's rule."""
|
||||
nonlocal hwm
|
||||
"""PCT of current WORKING equity, drawdown-braked, clamped — the copybot's
|
||||
rule. Sweeps surplus cash to the banked reserve first, so working equity
|
||||
stays at the level where stakes ~= STAKE_CAP."""
|
||||
nonlocal hwm, cash, reserve
|
||||
eq = cash + sum(c for _, c, _, _ in held)
|
||||
excess = eq - STAKE_CAP / PCT
|
||||
if excess > 0:
|
||||
sweep = min(cash, excess)
|
||||
cash -= sweep; reserve += sweep; eq -= sweep
|
||||
hwm = max(hwm, eq)
|
||||
frac = PCT * (DD_FACTOR if eq < DD_THRESHOLD * hwm else 1.0)
|
||||
return max(STAKE_MIN, min(STAKE_CAP, frac * eq))
|
||||
@@ -296,16 +306,18 @@ def main():
|
||||
for w in WALLETS:
|
||||
t = cache.conv_cutoff(b["size"] for b in cache.get_bets(w["wallet"]) if (b["size"] or 0) > 0)
|
||||
conv_thr[w["wallet"]] = round(t) if t != float("inf") else 1e12
|
||||
equity = cash + invested
|
||||
equity = cash + invested + reserve
|
||||
out = {
|
||||
"started": START, "updated": now,
|
||||
"bank": BANK, "stake": round(cur_stake(), 2), # the NEXT bet's size
|
||||
"stake_pct": PCT, "event_cap": EVENT_CAP, "hwm": round(hwm, 2),
|
||||
"stake_pct": PCT, "stake_cap": STAKE_CAP, "event_cap": EVENT_CAP,
|
||||
"hwm": round(hwm, 2),
|
||||
"dd_threshold": DD_THRESHOLD, "capped_count": capped,
|
||||
"max_entry": MAX_ENTRY,
|
||||
"fee_rate": FEE_RATE, "slip": SLIP, "lag_est_s": LAG_EST_S,
|
||||
"fees_paid": round(fees_paid, 2),
|
||||
"equity": round(equity, 2), "liquid": round(cash, 2), "invested": round(invested, 2),
|
||||
"reserve": round(reserve, 2), # banked profit, never bet
|
||||
"realized": round(realized, 2), "pnl": round(equity - BANK, 2),
|
||||
"unreal": round(invested - open_cost, 2),
|
||||
"resolved_count": len(resolved), "wins": wins, "losses": len(resolved) - wins,
|
||||
@@ -330,10 +342,10 @@ def main():
|
||||
json.dump(out, open(os.path.join(HERE, OUT) if not os.path.isabs(OUT) else OUT, "w"),
|
||||
separators=(",", ":"))
|
||||
save_slug_cache()
|
||||
print(f"portfolio: equity ${equity:,.0f} ({(equity-BANK)/BANK*100:+.0f}%) | realized ${realized:+,.0f} "
|
||||
f"| fees ${fees_paid:,.0f} | next stake ${cur_stake():,.0f} | {len(resolved)} resolved "
|
||||
f"({wins}W/{len(resolved)-wins}L) | {len(current)} open | {len(missed)} missed "
|
||||
f"({capped} event-capped) | -> portfolio.json", flush=True)
|
||||
print(f"portfolio: equity ${equity:,.0f} ({(equity-BANK)/BANK*100:+.0f}%) | banked ${reserve:,.0f} "
|
||||
f"| realized ${realized:+,.0f} | fees ${fees_paid:,.0f} | next stake ${cur_stake():,.0f} "
|
||||
f"| {len(resolved)} resolved ({wins}W/{len(resolved)-wins}L) | {len(current)} open "
|
||||
f"| {len(missed)} missed ({capped} event-capped) | -> portfolio.json", flush=True)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
Reference in New Issue
Block a user