From 7e9ccdf5c8f2b4402734de06e3c9f2b56062c539 Mon Sep 17 00:00:00 2001 From: jaxperro Date: Fri, 3 Jul 2026 00:49:21 -0400 Subject: [PATCH] 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 --- archive/copytrade.py | 30 ++++++++++++++++++++++++------ copybot.py | 12 ++++++++---- live/copybot.paper.json | 3 ++- live/portfolio.json | 2 +- live/portfolio.py | 30 +++++++++++++++++++++--------- 5 files changed, 56 insertions(+), 21 deletions(-) diff --git a/archive/copytrade.py b/archive/copytrade.py index e3af0680..1b9baacd 100644 --- a/archive/copytrade.py +++ b/archive/copytrade.py @@ -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 — diff --git a/copybot.py b/copybot.py index 3f3ff335..bfd8d7f4 100644 --- a/copybot.py +++ b/copybot.py @@ -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 "")) diff --git a/live/copybot.paper.json b/live/copybot.paper.json index 61df531b..6d46288e 100644 --- a/live/copybot.paper.json +++ b/live/copybot.paper.json @@ -55,5 +55,6 @@ "max_price": 0.99, "min_order_usd": 5.0, "max_per_event": 0 - } + }, + "stake_cap_usd": 250.0 } \ No newline at end of file diff --git a/live/portfolio.json b/live/portfolio.json index d7c53dbb..90bc8bd5 100644 --- a/live/portfolio.json +++ b/live/portfolio.json @@ -1 +1 @@ -{"started":1780286400.0,"updated":1783053657.3556852,"bank":1000.0,"stake":1070.25,"stake_pct":0.04,"event_cap":0,"hwm":26773.07,"dd_threshold":0.8,"capped_count":0,"max_entry":0.95,"fee_rate":0.03,"slip":0.005,"lag_est_s":90,"fees_paid":1530.99,"equity":27766.37,"liquid":24422.5,"invested":3343.87,"realized":25756.25,"pnl":26766.37,"unreal":1010.12,"resolved_count":400,"wins":311,"losses":89,"open_count":7,"missed_count":25,"wallets":[{"name":"Kruto2027","wallet":"0xe8ca3f758c93f44f3ec210542ab78afb7c0bcccb","bets":42,"won":31,"lost":8,"invested":3180.83,"realized":3578.89,"conv_thr":123},{"name":"shisan888","wallet":"0xf3488e52ac2d7f0628b04481db5a5b0446f0e543","bets":44,"won":33,"lost":8,"invested":122.09,"realized":2995.56,"conv_thr":727},{"name":"fortuneking","wallet":"0x86c878cde72660ec52f5e6f0f0438b76de8fc867","bets":85,"won":57,"lost":27,"invested":40.95,"realized":-747.38,"conv_thr":1000},{"name":"LSB1","wallet":"0x41558102a796ba971c7567cad41c307e59f8fa41","bets":108,"won":98,"lost":10,"invested":0.0,"realized":5331.0,"conv_thr":231},{"name":"imwalkinghere","wallet":"0xd96750bf8d941a8186e592b0ae6e096da66aa266","bets":128,"won":92,"lost":36,"invested":0.0,"realized":14598.18,"conv_thr":115}],"current":[{"title":"Switzerland vs. Algeria: O/U 8.5 Total Corners","name":"shisan888","outcome":"Under","stake":40.0,"val":62.29,"pnl":21.7,"end":"2026-07-03"},{"title":"Switzerland vs. Algeria: O/U 6.5 Total Corners","name":"shisan888","outcome":"Under","stake":40.0,"val":19.69,"pnl":-21.12,"end":"2026-07-03"},{"title":"Switzerland vs. Algeria: O/U 7.5 Total Corners","name":"shisan888","outcome":"Under","stake":40.0,"val":40.12,"pnl":-0.54,"end":"2026-07-03"},{"title":"Spread: Club ABB (-1.5)","name":"Kruto2027","outcome":"Bamin Real Potos\u00ed","stake":40.0,"val":31.2,"pnl":-9.14,"end":"2026-05-14"},{"title":"Club Always Ready vs. FC Universitario: O/U 4.5","name":"fortuneking","outcome":"Under","stake":40.0,"val":40.95,"pnl":0.35,"end":"2026-05-23"},{"title":"Washington Spirit vs. Houston Dash: 2nd Half O/U 1.5","name":"Kruto2027","outcome":"Over","stake":1047.09,"val":1378.43,"pnl":311.98,"end":"2026-07-04"},{"title":"Washington Spirit vs. Houston Dash: Washington Spirit 2nd Half O/U 0.5","name":"Kruto2027","outcome":"Over","stake":1047.09,"val":1771.19,"pnl":706.9,"end":"2026-07-04"}],"resolved":[{"title":"ITF Taipei: Priska Madelyn Nugroho vs Dayeon Back","name":"fortuneking","won":true,"stake":922.8,"pnl":534.72,"date":1783051200},{"title":"Lexus Eastbourne Open: Zizou Bergs vs Toby Samuel","name":"fortuneking","won":false,"stake":922.8,"pnl":-930.18,"date":1783051200},{"title":"ITF Zagreb: Dorian Tremblay vs Javier Barranco Cosano","name":"fortuneking","won":true,"stake":964.37,"pnl":122.71,"date":1782964800},{"title":"Mallorca Championships: Luciano Darderi vs Nuno Borges","name":"fortuneking","won":true,"stake":964.37,"pnl":78.41,"date":1782964800},{"title":"ITF Palma Del Rio: Ayla Aksu vs Celia Cervino Ruiz","name":"fortuneking","won":true,"stake":925.15,"pnl":279.55,"date":1782964800},{"title":"Bitcoin Up or Down - July 2, 1:10AM-1:15AM ET","name":"imwalkinghere","won":true,"stake":1066.31,"pnl":493.86,"date":1782964800},{"title":"Bitcoin Up or Down - June 30, 7:55PM-8:00PM ET","name":"imwalkinghere","won":true,"stake":1018.09,"pnl":724.98,"date":1782878400},{"title":"ITF Tarvisio: Gabriela Ce vs Pia Lovric","name":"fortuneking","won":true,"stake":964.9,"pnl":549.21,"date":1782792000},{"title":"ITF Palma Del Rio: Polina Isakova vs Anna Kubareva","name":"fortuneking","won":true,"stake":964.9,"pnl":137.37,"date":1782792000},{"title":"ITF Palma Del Rio: Tiphanie Lemaitre vs Kristina Mladenovic","name":"fortuneking","won":true,"stake":938.49,"pnl":156.02,"date":1782792000},{"title":"Piracicaba: Luis Felipe Miguel vs Thiago Seyboth Wild","name":"fortuneking","won":true,"stake":925.15,"pnl":141.49,"date":1782792000},{"title":"Bitcoin Up or Down - June 29, 7:55PM-8:00PM ET","name":"imwalkinghere","won":true,"stake":1000.46,"pnl":515.75,"date":1782792000},{"title":"Will Morocco win on 2026-06-29?","name":"imwalkinghere","won":false,"stake":1000.46,"pnl":-1022.94,"date":1782792000},{"title":"Bitcoin Up or Down - June 29, 10:30PM-10:35PM ET","name":"imwalkinghere","won":true,"stake":1000.46,"pnl":535.82,"date":1782792000},{"title":"Bitcoin Up or Down - June 29, 10:40PM-10:45PM ET","name":"imwalkinghere","won":true,"stake":1000.46,"pnl":748.77,"date":1782792000},{"title":"Bitcoin Up or Down - June 30, 4:45AM-4:50AM ET","name":"imwalkinghere","won":false,"stake":1070.92,"pnl":-1088.61,"date":1782792000},{"title":"Bitcoin Up or Down - June 30, 6:10AM-6:15AM ET","name":"imwalkinghere","won":false,"stake":1027.38,"pnl":-1039.18,"date":1782792000},{"title":"Bitcoin Up or Down - June 30, 1:05PM-1:10PM ET","name":"imwalkinghere","won":true,"stake":985.81,"pnl":241.1,"date":1782792000},{"title":"France vs. Sweden: Both Teams to Score in Second Half","name":"fortuneking","won":true,"stake":995.46,"pnl":565.82,"date":1782792000},{"title":"ITF Palma Del Rio: Eva Vedder vs Zoziya Kardava","name":"fortuneking","won":true,"stake":647.79,"pnl":35.53,"date":1782705600},{"title":"Lexus Eastbourne Open: Sara Bejlek vs Laura Siegemund","name":"fortuneking","won":false,"stake":946.67,"pnl":-956.19,"date":1782705600},{"title":"Bitcoin Up or Down - June 28, 9:45PM-9:50PM ET","name":"imwalkinghere","won":true,"stake":968.55,"pnl":826.16,"date":1782705600},{"title":"Map 2 Rounds Handicap: Donstu Esports (-3.5) vs OlyBet SB (+3.5)","name":"Kruto2027","won":false,"stake":964.77,"pnl":-985.86,"date":1782705600},{"title":"Counter-Strike: OlyBet SB vs Donstu Esports - Map 2 Winner","name":"Kruto2027","won":true,"stake":925.33,"pnl":122.31,"date":1782705600},{"title":"Germany vs. Paraguay: O/U 10.5 Total Corners","name":"Kruto2027","won":true,"stake":930.23,"pnl":1152.41,"date":1782705600},{"title":"Bitcoin Up or Down - June 29, 4:35PM-4:40PM ET","name":"imwalkinghere","won":true,"stake":976.32,"pnl":603.56,"date":1782705600},{"title":"ITF Samobor: Andrej Nedic vs Nikita Mashtakov","name":"fortuneking","won":false,"stake":686.76,"pnl":-694.52,"date":1782619200},{"title":"Bitcoin Up or Down - June 28, 6:00AM-6:15AM ET","name":"imwalkinghere","won":true,"stake":961.06,"pnl":187.18,"date":1782619200},{"title":"Mallorca Championships, Qualification: Adam Walton vs Federico Bondioli","name":"fortuneking","won":true,"stake":517.58,"pnl":24.62,"date":1782532800},{"title":"Grass Court Championships: Aryna Sabalenka vs Jessica Pegula","name":"fortuneking","won":true,"stake":528.15,"pnl":149.19,"date":1782532800},{"title":"Halle Open: Alexander Zverev vs Taylor Fritz","name":"fortuneking","won":true,"stake":528.15,"pnl":313.5,"date":1782532800},{"title":"Uruguay vs. Spain: O/U 11.5 Total Corners","name":"fortuneking","won":true,"stake":891.82,"pnl":1065.49,"date":1782532800},{"title":"Bitcoin Up or Down - June 27, 5:20AM-5:25AM ET","name":"imwalkinghere","won":true,"stake":953.94,"pnl":485.63,"date":1782532800},{"title":"Bitcoin Up or Down - June 27, 11:20AM-11:25AM ET","name":"imwalkinghere","won":false,"stake":973.36,"pnl":-979.68,"date":1782532800},{"title":"Panama vs. England: O/U 10.5 Total Corners","name":"fortuneking","won":true,"stake":934.17,"pnl":910.94,"date":1782532800},{"title":"Bitcoin Up or Down - June 27, 7:15PM-7:20PM ET","name":"imwalkinghere","won":true,"stake":970.61,"pnl":455.74,"date":1782532800},{"title":"Dart/Lumsden vs. Sutjiadi/Tjen: Set 2 Games O/U 9.5","name":"fortuneking","won":true,"stake":394.52,"pnl":651.82,"date":1782446400},{"title":"Will Racing 92 win?","name":"fortuneking","won":true,"stake":394.52,"pnl":140.08,"date":1782446400},{"title":"Paraguay vs. Australia: Australia O/U 2.5 Corners","name":"Kruto2027","won":true,"stake":851.64,"pnl":809.55,"date":1782446400},{"title":"Bitcoin Up or Down - June 26, 3:30AM-3:45AM ET","name":"imwalkinghere","won":true,"stake":915.7,"pnl":177.51,"date":1782446400},{"title":"Bitcoin Up or Down - June 26, 2:05PM-2:10PM ET","name":"imwalkinghere","won":false,"stake":922.8,"pnl":-933.73,"date":1782446400},{"title":"Norway vs. France: O/U 12.5 Total Corners","name":"fortuneking","won":true,"stake":885.45,"pnl":159.27,"date":1782446400},{"title":"Parma: Laslo Djere vs Chun-Hsin Tseng","name":"fortuneking","won":false,"stake":290.33,"pnl":-295.49,"date":1782360000},{"title":"Bitcoin Up or Down - June 24, 9:05PM-9:10PM ET","name":"imwalkinghere","won":true,"stake":973.81,"pnl":440.21,"date":1782360000},{"title":"Bitcoin Up or Down - June 24, 9:10PM-9:15PM ET","name":"imwalkinghere","won":true,"stake":934.57,"pnl":600.07,"date":1782360000},{"title":"Bitcoin Up or Down - June 25, 3:20PM-3:25PM ET","name":"imwalkinghere","won":false,"stake":964.37,"pnl":-980.42,"date":1782360000},{"title":"Japan vs. Sweden: O/U 7.5 Total Corners","name":"fortuneking","won":false,"stake":925.15,"pnl":-936.45,"date":1782360000},{"title":"Japan vs. Sweden: O/U 9.5 Total Corners","name":"fortuneking","won":false,"stake":887.69,"pnl":-901.21,"date":1782360000},{"title":"ICC T20 World Cup, Women: Australia vs Bangladesh","name":"Kruto2027","won":false,"stake":165.8,"pnl":-170.05,"date":1782273600},{"title":"Royan: Leo Raquillet vs Pavel Kotov","name":"Kruto2027","won":false,"stake":250.62,"pnl":-257.57,"date":1782273600},{"title":"Mees Rottgering vs. Kyrian Jacquet: Total Sets O/U 2.5","name":"Kruto2027","won":true,"stake":250.62,"pnl":234.68,"date":1782273600},{"title":"Bitcoin Up or Down - June 23, 11:00PM-11:05PM ET","name":"imwalkinghere","won":true,"stake":1009.43,"pnl":410.09,"date":1782273600},{"title":"Games Total: O/U 2.5","name":"Kruto2027","won":true,"stake":1018.12,"pnl":810.13,"date":1782273600},{"title":"Bitcoin Up or Down - June 24, 10:15AM-10:30AM ET","name":"imwalkinghere","won":true,"stake":1050.52,"pnl":298.12,"date":1782273600},{"title":"Ethereum Up or Down - June 24, 1:30PM-1:35PM ET","name":"imwalkinghere","won":false,"stake":1062.45,"pnl":-1076.46,"date":1782273600},{"title":"Switzerland vs. Canada: O/U 8.5 Total Corners","name":"fortuneking","won":false,"stake":1019.39,"pnl":-1030.91,"date":1782273600},{"title":"Switzerland vs. Canada: O/U 7.5 Total Corners","name":"fortuneking","won":false,"stake":978.15,"pnl":-991.54,"date":1782273600},{"title":"Morocco vs. Haiti: Morocco 1st Half O/U 1.5","name":"imwalkinghere","won":true,"stake":938.49,"pnl":1759.33,"date":1782273600},{"title":"Spread: Morocco (-1.5)","name":"fortuneking","won":false,"stake":1008.86,"pnl":-1018.44,"date":1782273600},{"title":"Morocco vs. Haiti: O/U 7.5","name":"fortuneking","won":true,"stake":968.12,"pnl":142.26,"date":1782273600}],"missed":[{"title":"ITF Kayseri: Ustiniya Lekomtseva vs Sofiia Bielinska","name":"Kruto2027","won":true,"stake":61.95,"capped":false,"pnl":24.35,"date":1781755200},{"title":"Tucuman: Federico Coria vs Andrea Collarini","name":"fortuneking","won":true,"stake":68.41,"capped":false,"pnl":50.13,"date":1781755200},{"title":"ITF Merzig: Sonja Zhenikhova vs Leonie Schuknecht","name":"Kruto2027","won":false,"stake":63.92,"capped":false,"pnl":-64.66,"date":1781668800},{"title":"Lyon: Nikolas Sanchez Izquierdo vs Luca Van Assche","name":"fortuneking","won":true,"stake":61.95,"capped":false,"pnl":138.13,"date":1781668800},{"title":"IR Iran vs. New Zealand: Both Teams to Score in First Half","name":"Kruto2027","won":false,"stake":68.41,"capped":false,"pnl":-68.98,"date":1781582400},{"title":"Australia vs. T\u00fcrkiye: Australia O/U 2.5","name":"Kruto2027","won":true,"stake":63.92,"capped":false,"pnl":46.38,"date":1781409600},{"title":"Australia vs. T\u00fcrkiye: Australia O/U 1.5","name":"Kruto2027","won":false,"stake":63.92,"capped":false,"pnl":-65.28,"date":1781409600},{"title":"Folarin Balogun: 1+ goals","name":"LSB1","won":true,"stake":70.15,"capped":false,"pnl":133.76,"date":1781330400},{"title":"Exact Score: United States 2 - 0 Paraguay?","name":"LSB1","won":true,"stake":70.15,"capped":false,"pnl":11.47,"date":1781330400},{"title":"Exact Score: United States 3 - 0 Paraguay?","name":"LSB1","won":true,"stake":70.15,"capped":false,"pnl":3.47,"date":1781330400},{"title":"Qatar vs. Switzerland: 1st Half O/U 1.5","name":"Kruto2027","won":true,"stake":63.92,"capped":false,"pnl":62.33,"date":1781323200},{"title":"Exact Score: Korea Republic 2 - 0 Czechia?","name":"LSB1","won":true,"stake":68.41,"capped":false,"pnl":3.44,"date":1781244000},{"title":"Exact Score: Korea Republic 1 - 0 Czechia?","name":"LSB1","won":true,"stake":68.41,"capped":false,"pnl":12.55,"date":1781244000},{"title":"Will CR Brasil win on 2026-06-12?","name":"LSB1","won":false,"stake":70.15,"capped":false,"pnl":-70.51,"date":1781244000},{"title":"Bitcoin Up or Down - June 11, 7:55PM-8:00PM ET","name":"imwalkinghere","won":true,"stake":68.41,"capped":false,"pnl":19.38,"date":1781236800},{"title":"BNB Up or Down - June 12, 11:35AM-11:40AM ET","name":"imwalkinghere","won":true,"stake":70.15,"capped":false,"pnl":50.87,"date":1781236800},{"title":"Canada vs. Bosnia and Herzegovina: O/U 2.5","name":"imwalkinghere","won":true,"stake":70.15,"capped":false,"pnl":71.76,"date":1781236800},{"title":"Bitcoin Up or Down - June 12, 6:45PM-6:50PM ET","name":"imwalkinghere","won":false,"stake":70.15,"capped":false,"pnl":-71.07,"date":1781236800},{"title":"Bolivia vs. Algeria: Bolivia O/U 2.5","name":"Kruto2027","won":true,"stake":63.92,"capped":false,"pnl":52.05,"date":1781150400},{"title":"Bitcoin Up or Down - June 10, 11:15PM-11:20PM ET","name":"imwalkinghere","won":true,"stake":61.95,"capped":false,"pnl":30.19,"date":1781150400},{"title":"Iraq vs. Venezuela: Iraq O/U 1.5","name":"Kruto2027","won":true,"stake":63.92,"capped":false,"pnl":86.23,"date":1781064000},{"title":"Portugal vs. Nigeria: Portugal O/U 1.5","name":"Kruto2027","won":false,"stake":63.92,"capped":false,"pnl":-65.48,"date":1781064000},{"title":"Bitcoin Up or Down - June 10, 11:00AM-11:05AM ET","name":"imwalkinghere","won":false,"stake":61.95,"capped":false,"pnl":-63.03,"date":1781064000},{"title":"Bitcoin Up or Down - June 10, 11:10AM-11:15AM ET","name":"imwalkinghere","won":false,"stake":61.95,"capped":false,"pnl":-62.93,"date":1781064000},{"title":"BNB Up or Down - June 10, 6:50PM-6:55PM ET","name":"imwalkinghere","won":false,"stake":61.95,"capped":false,"pnl":-62.76,"date":1781064000}],"missed_pnl":201.8} \ No newline at end of file +{"started":1780286400.0,"updated":1783054133.3771222,"bank":1000.0,"stake":249.66,"stake_pct":0.04,"stake_cap":250.0,"event_cap":0,"hwm":6250.0,"dd_threshold":0.8,"capped_count":0,"max_entry":0.95,"fee_rate":0.03,"slip":0.005,"lag_est_s":90,"fees_paid":693.1,"equity":15684.27,"liquid":5541.32,"invested":958.33,"reserve":9184.62,"realized":14426.18,"pnl":14684.27,"unreal":258.09,"resolved_count":400,"wins":311,"losses":89,"open_count":7,"missed_count":25,"wallets":[{"name":"Kruto2027","wallet":"0xe8ca3f758c93f44f3ec210542ab78afb7c0bcccb","bets":42,"won":31,"lost":8,"invested":766.46,"realized":1920.24,"conv_thr":123},{"name":"shisan888","wallet":"0xf3488e52ac2d7f0628b04481db5a5b0446f0e543","bets":44,"won":33,"lost":8,"invested":150.91,"realized":1768.55,"conv_thr":727},{"name":"fortuneking","wallet":"0x86c878cde72660ec52f5e6f0f0438b76de8fc867","bets":85,"won":57,"lost":27,"invested":40.95,"realized":1259.48,"conv_thr":1000},{"name":"LSB1","wallet":"0x41558102a796ba971c7567cad41c307e59f8fa41","bets":108,"won":98,"lost":10,"invested":0.0,"realized":3182.4,"conv_thr":231},{"name":"imwalkinghere","wallet":"0xd96750bf8d941a8186e592b0ae6e096da66aa266","bets":128,"won":92,"lost":36,"invested":0.0,"realized":6295.51,"conv_thr":115}],"current":[{"title":"Switzerland vs. Algeria: O/U 8.5 Total Corners","name":"shisan888","outcome":"Under","stake":40.0,"val":69.73,"pnl":29.14,"end":"2026-07-03"},{"title":"Switzerland vs. Algeria: O/U 6.5 Total Corners","name":"shisan888","outcome":"Under","stake":40.0,"val":35.0,"pnl":-5.81,"end":"2026-07-03"},{"title":"Switzerland vs. Algeria: O/U 7.5 Total Corners","name":"shisan888","outcome":"Under","stake":40.0,"val":46.19,"pnl":5.7,"end":"2026-07-03"},{"title":"Spread: Club ABB (-1.5)","name":"Kruto2027","outcome":"Bamin Real Potos\u00ed","stake":40.0,"val":31.2,"pnl":-9.14,"end":"2026-05-14"},{"title":"Club Always Ready vs. FC Universitario: O/U 4.5","name":"fortuneking","outcome":"Under","stake":40.0,"val":40.95,"pnl":0.35,"end":"2026-05-23"},{"title":"Washington Spirit vs. Houston Dash: 2nd Half O/U 1.5","name":"Kruto2027","outcome":"Over","stake":244.44,"val":321.79,"pnl":72.83,"end":"2026-07-04"},{"title":"Washington Spirit vs. Houston Dash: Washington Spirit 2nd Half O/U 0.5","name":"Kruto2027","outcome":"Over","stake":244.44,"val":413.47,"pnl":165.02,"end":"2026-07-04"}],"resolved":[{"title":"ITF Taipei: Priska Madelyn Nugroho vs Dayeon Back","name":"fortuneking","won":true,"stake":219.31,"pnl":127.08,"date":1783051200},{"title":"Lexus Eastbourne Open: Zizou Bergs vs Toby Samuel","name":"fortuneking","won":false,"stake":219.31,"pnl":-221.06,"date":1783051200},{"title":"ITF Zagreb: Dorian Tremblay vs Javier Barranco Cosano","name":"fortuneking","won":true,"stake":219.52,"pnl":27.93,"date":1782964800},{"title":"Mallorca Championships: Luciano Darderi vs Nuno Borges","name":"fortuneking","won":true,"stake":219.52,"pnl":17.85,"date":1782964800},{"title":"ITF Palma Del Rio: Ayla Aksu vs Celia Cervino Ruiz","name":"fortuneking","won":true,"stake":210.6,"pnl":63.64,"date":1782964800},{"title":"Bitcoin Up or Down - July 2, 1:10AM-1:15AM ET","name":"imwalkinghere","won":true,"stake":248.81,"pnl":115.24,"date":1782964800},{"title":"Bitcoin Up or Down - June 30, 7:55PM-8:00PM ET","name":"imwalkinghere","won":true,"stake":237.67,"pnl":169.24,"date":1782878400},{"title":"ITF Tarvisio: Gabriela Ce vs Pia Lovric","name":"fortuneking","won":true,"stake":250.0,"pnl":142.3,"date":1782792000},{"title":"ITF Palma Del Rio: Polina Isakova vs Anna Kubareva","name":"fortuneking","won":true,"stake":250.0,"pnl":35.59,"date":1782792000},{"title":"ITF Palma Del Rio: Tiphanie Lemaitre vs Kristina Mladenovic","name":"fortuneking","won":true,"stake":220.83,"pnl":36.71,"date":1782792000},{"title":"Piracicaba: Luis Felipe Miguel vs Thiago Seyboth Wild","name":"fortuneking","won":true,"stake":210.6,"pnl":32.21,"date":1782792000},{"title":"Bitcoin Up or Down - June 29, 7:55PM-8:00PM ET","name":"imwalkinghere","won":true,"stake":238.19,"pnl":122.79,"date":1782792000},{"title":"Will Morocco win on 2026-06-29?","name":"imwalkinghere","won":false,"stake":238.19,"pnl":-243.54,"date":1782792000},{"title":"Bitcoin Up or Down - June 29, 10:30PM-10:35PM ET","name":"imwalkinghere","won":true,"stake":238.19,"pnl":127.57,"date":1782792000},{"title":"Bitcoin Up or Down - June 29, 10:40PM-10:45PM ET","name":"imwalkinghere","won":true,"stake":238.19,"pnl":178.26,"date":1782792000},{"title":"Bitcoin Up or Down - June 30, 4:45AM-4:50AM ET","name":"imwalkinghere","won":false,"stake":250.0,"pnl":-254.13,"date":1782792000},{"title":"Bitcoin Up or Down - June 30, 6:10AM-6:15AM ET","name":"imwalkinghere","won":false,"stake":239.83,"pnl":-242.59,"date":1782792000},{"title":"Bitcoin Up or Down - June 30, 1:05PM-1:10PM ET","name":"imwalkinghere","won":true,"stake":230.13,"pnl":56.28,"date":1782792000},{"title":"France vs. Sweden: Both Teams to Score in Second Half","name":"fortuneking","won":true,"stake":232.38,"pnl":132.09,"date":1782792000},{"title":"ITF Palma Del Rio: Eva Vedder vs Zoziya Kardava","name":"fortuneking","won":true,"stake":200.28,"pnl":10.99,"date":1782705600},{"title":"Lexus Eastbourne Open: Sara Bejlek vs Laura Siegemund","name":"fortuneking","won":false,"stake":250.0,"pnl":-252.51,"date":1782705600},{"title":"Bitcoin Up or Down - June 28, 9:45PM-9:50PM ET","name":"imwalkinghere","won":true,"stake":231.45,"pnl":197.43,"date":1782705600},{"title":"Map 2 Rounds Handicap: Donstu Esports (-3.5) vs OlyBet SB (+3.5)","name":"Kruto2027","won":false,"stake":229.69,"pnl":-234.71,"date":1782705600},{"title":"Counter-Strike: OlyBet SB vs Donstu Esports - Map 2 Winner","name":"Kruto2027","won":true,"stake":220.3,"pnl":29.12,"date":1782705600},{"title":"Germany vs. Paraguay: O/U 10.5 Total Corners","name":"Kruto2027","won":true,"stake":221.46,"pnl":274.36,"date":1782705600},{"title":"Bitcoin Up or Down - June 29, 4:35PM-4:40PM ET","name":"imwalkinghere","won":true,"stake":232.44,"pnl":143.69,"date":1782705600},{"title":"ITF Samobor: Andrej Nedic vs Nikita Mashtakov","name":"fortuneking","won":false,"stake":250.0,"pnl":-252.83,"date":1782619200},{"title":"Bitcoin Up or Down - June 28, 6:00AM-6:15AM ET","name":"imwalkinghere","won":true,"stake":229.66,"pnl":44.73,"date":1782619200},{"title":"Mallorca Championships, Qualification: Adam Walton vs Federico Bondioli","name":"fortuneking","won":true,"stake":249.38,"pnl":11.86,"date":1782532800},{"title":"Grass Court Championships: Aryna Sabalenka vs Jessica Pegula","name":"fortuneking","won":true,"stake":250.0,"pnl":70.62,"date":1782532800},{"title":"Halle Open: Alexander Zverev vs Taylor Fritz","name":"fortuneking","won":true,"stake":250.0,"pnl":148.4,"date":1782532800},{"title":"Uruguay vs. Spain: O/U 11.5 Total Corners","name":"fortuneking","won":true,"stake":211.95,"pnl":253.22,"date":1782532800},{"title":"Bitcoin Up or Down - June 27, 5:20AM-5:25AM ET","name":"imwalkinghere","won":true,"stake":231.31,"pnl":117.76,"date":1782532800},{"title":"Bitcoin Up or Down - June 27, 11:20AM-11:25AM ET","name":"imwalkinghere","won":false,"stake":236.02,"pnl":-237.55,"date":1782532800},{"title":"Panama vs. England: O/U 10.5 Total Corners","name":"fortuneking","won":true,"stake":226.52,"pnl":220.89,"date":1782532800},{"title":"Bitcoin Up or Down - June 27, 7:15PM-7:20PM ET","name":"imwalkinghere","won":true,"stake":235.36,"pnl":110.51,"date":1782532800},{"title":"Dart/Lumsden vs. Sutjiadi/Tjen: Set 2 Games O/U 9.5","name":"fortuneking","won":true,"stake":250.0,"pnl":413.05,"date":1782446400},{"title":"Will Racing 92 win?","name":"fortuneking","won":true,"stake":250.0,"pnl":88.76,"date":1782446400},{"title":"Paraguay vs. Australia: Australia O/U 2.5 Corners","name":"Kruto2027","won":true,"stake":96.93,"pnl":92.14,"date":1782446400},{"title":"Bitcoin Up or Down - June 26, 3:30AM-3:45AM ET","name":"imwalkinghere","won":true,"stake":217.62,"pnl":42.19,"date":1782446400},{"title":"Bitcoin Up or Down - June 26, 2:05PM-2:10PM ET","name":"imwalkinghere","won":false,"stake":219.31,"pnl":-221.91,"date":1782446400},{"title":"Norway vs. France: O/U 12.5 Total Corners","name":"fortuneking","won":true,"stake":210.43,"pnl":37.85,"date":1782446400},{"title":"Parma: Laslo Djere vs Chun-Hsin Tseng","name":"fortuneking","won":false,"stake":250.0,"pnl":-254.44,"date":1782360000},{"title":"Bitcoin Up or Down - June 24, 9:05PM-9:10PM ET","name":"imwalkinghere","won":true,"stake":229.14,"pnl":103.58,"date":1782360000},{"title":"Bitcoin Up or Down - June 24, 9:10PM-9:15PM ET","name":"imwalkinghere","won":true,"stake":219.91,"pnl":141.2,"date":1782360000},{"title":"Bitcoin Up or Down - June 25, 3:20PM-3:25PM ET","name":"imwalkinghere","won":false,"stake":219.52,"pnl":-223.18,"date":1782360000},{"title":"Japan vs. Sweden: O/U 7.5 Total Corners","name":"fortuneking","won":false,"stake":210.6,"pnl":-213.17,"date":1782360000},{"title":"Japan vs. Sweden: O/U 9.5 Total Corners","name":"fortuneking","won":false,"stake":202.07,"pnl":-205.15,"date":1782360000},{"title":"ICC T20 World Cup, Women: Australia vs Bangladesh","name":"Kruto2027","won":false,"stake":165.8,"pnl":-170.05,"date":1782273600},{"title":"Royan: Leo Raquillet vs Pavel Kotov","name":"Kruto2027","won":false,"stake":250.0,"pnl":-256.93,"date":1782273600},{"title":"Mees Rottgering vs. Kyrian Jacquet: Total Sets O/U 2.5","name":"Kruto2027","won":true,"stake":250.0,"pnl":234.1,"date":1782273600},{"title":"Bitcoin Up or Down - June 23, 11:00PM-11:05PM ET","name":"imwalkinghere","won":true,"stake":250.0,"pnl":101.57,"date":1782273600},{"title":"Games Total: O/U 2.5","name":"Kruto2027","won":true,"stake":246.35,"pnl":196.02,"date":1782273600},{"title":"Bitcoin Up or Down - June 24, 10:15AM-10:30AM ET","name":"imwalkinghere","won":true,"stake":250.0,"pnl":70.95,"date":1782273600},{"title":"Ethereum Up or Down - June 24, 1:30PM-1:35PM ET","name":"imwalkinghere","won":false,"stake":250.0,"pnl":-253.3,"date":1782273600},{"title":"Switzerland vs. Canada: O/U 8.5 Total Corners","name":"fortuneking","won":false,"stake":239.87,"pnl":-242.58,"date":1782273600},{"title":"Switzerland vs. Canada: O/U 7.5 Total Corners","name":"fortuneking","won":false,"stake":230.16,"pnl":-233.32,"date":1782273600},{"title":"Morocco vs. Haiti: Morocco 1st Half O/U 1.5","name":"imwalkinghere","won":true,"stake":220.83,"pnl":413.98,"date":1782273600},{"title":"Spread: Morocco (-1.5)","name":"fortuneking","won":false,"stake":237.39,"pnl":-239.65,"date":1782273600},{"title":"Morocco vs. Haiti: O/U 7.5","name":"fortuneking","won":true,"stake":227.81,"pnl":33.47,"date":1782273600}],"missed":[{"title":"ITF Kayseri: Ustiniya Lekomtseva vs Sofiia Bielinska","name":"Kruto2027","won":true,"stake":61.95,"capped":false,"pnl":24.35,"date":1781755200},{"title":"Tucuman: Federico Coria vs Andrea Collarini","name":"fortuneking","won":true,"stake":68.41,"capped":false,"pnl":50.13,"date":1781755200},{"title":"ITF Merzig: Sonja Zhenikhova vs Leonie Schuknecht","name":"Kruto2027","won":false,"stake":63.92,"capped":false,"pnl":-64.66,"date":1781668800},{"title":"Lyon: Nikolas Sanchez Izquierdo vs Luca Van Assche","name":"fortuneking","won":true,"stake":61.95,"capped":false,"pnl":138.13,"date":1781668800},{"title":"IR Iran vs. New Zealand: Both Teams to Score in First Half","name":"Kruto2027","won":false,"stake":68.41,"capped":false,"pnl":-68.98,"date":1781582400},{"title":"Australia vs. T\u00fcrkiye: Australia O/U 2.5","name":"Kruto2027","won":true,"stake":63.92,"capped":false,"pnl":46.38,"date":1781409600},{"title":"Australia vs. T\u00fcrkiye: Australia O/U 1.5","name":"Kruto2027","won":false,"stake":63.92,"capped":false,"pnl":-65.28,"date":1781409600},{"title":"Folarin Balogun: 1+ goals","name":"LSB1","won":true,"stake":70.15,"capped":false,"pnl":133.76,"date":1781330400},{"title":"Exact Score: United States 2 - 0 Paraguay?","name":"LSB1","won":true,"stake":70.15,"capped":false,"pnl":11.47,"date":1781330400},{"title":"Exact Score: United States 3 - 0 Paraguay?","name":"LSB1","won":true,"stake":70.15,"capped":false,"pnl":3.47,"date":1781330400},{"title":"Qatar vs. Switzerland: 1st Half O/U 1.5","name":"Kruto2027","won":true,"stake":63.92,"capped":false,"pnl":62.33,"date":1781323200},{"title":"Exact Score: Korea Republic 2 - 0 Czechia?","name":"LSB1","won":true,"stake":68.41,"capped":false,"pnl":3.44,"date":1781244000},{"title":"Exact Score: Korea Republic 1 - 0 Czechia?","name":"LSB1","won":true,"stake":68.41,"capped":false,"pnl":12.55,"date":1781244000},{"title":"Will CR Brasil win on 2026-06-12?","name":"LSB1","won":false,"stake":70.15,"capped":false,"pnl":-70.51,"date":1781244000},{"title":"Bitcoin Up or Down - June 11, 7:55PM-8:00PM ET","name":"imwalkinghere","won":true,"stake":68.41,"capped":false,"pnl":19.38,"date":1781236800},{"title":"BNB Up or Down - June 12, 11:35AM-11:40AM ET","name":"imwalkinghere","won":true,"stake":70.15,"capped":false,"pnl":50.87,"date":1781236800},{"title":"Canada vs. Bosnia and Herzegovina: O/U 2.5","name":"imwalkinghere","won":true,"stake":70.15,"capped":false,"pnl":71.76,"date":1781236800},{"title":"Bitcoin Up or Down - June 12, 6:45PM-6:50PM ET","name":"imwalkinghere","won":false,"stake":70.15,"capped":false,"pnl":-71.07,"date":1781236800},{"title":"Bolivia vs. Algeria: Bolivia O/U 2.5","name":"Kruto2027","won":true,"stake":63.92,"capped":false,"pnl":52.05,"date":1781150400},{"title":"Bitcoin Up or Down - June 10, 11:15PM-11:20PM ET","name":"imwalkinghere","won":true,"stake":61.95,"capped":false,"pnl":30.19,"date":1781150400},{"title":"Iraq vs. Venezuela: Iraq O/U 1.5","name":"Kruto2027","won":true,"stake":63.92,"capped":false,"pnl":86.23,"date":1781064000},{"title":"Portugal vs. Nigeria: Portugal O/U 1.5","name":"Kruto2027","won":false,"stake":63.92,"capped":false,"pnl":-65.48,"date":1781064000},{"title":"Bitcoin Up or Down - June 10, 11:00AM-11:05AM ET","name":"imwalkinghere","won":false,"stake":61.95,"capped":false,"pnl":-63.03,"date":1781064000},{"title":"Bitcoin Up or Down - June 10, 11:10AM-11:15AM ET","name":"imwalkinghere","won":false,"stake":61.95,"capped":false,"pnl":-62.93,"date":1781064000},{"title":"BNB Up or Down - June 10, 6:50PM-6:55PM ET","name":"imwalkinghere","won":false,"stake":61.95,"capped":false,"pnl":-62.76,"date":1781064000}],"missed_pnl":201.8} \ No newline at end of file diff --git a/live/portfolio.py b/live/portfolio.py index a721b378..6187a5a4 100644 --- a/live/portfolio.py +++ b/live/portfolio.py @@ -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__":