# capital_manager.py # Four‑tier compounding engine + dynamic risk pool + circuit breaker. # Now supports virtual mode (reads/writes an independent state file). # All comments in English. import os import json import time from datetime import datetime, timezone # ── File paths ────────────────────────────────────────── STATE_FILE = "/app/capital_state.json" ORIGINAL_DEPOSIT_FILE = "/app/original_deposit.json" BALANCE_FILE = "/app/balance.txt" VIRTUAL_STATE_FILE = "/app/virtual_capital_state.json" # ── Defaults ──────────────────────────────────────────── DEFAULT_RISK_POOL = 5.0 DEFAULT_TOTAL_CAPITAL = 20.0 HALT_FILE = "/app/halt_trading.txt" UNHALT_FILE = "/app/unhalt_trading.txt" # ── Compounding tiers ─────────────────────────────────── TIERS = [ (0.25, 10, "L1"), (0.50, 20, "L2"), (0.75, 30, "L3"), (0.90, 70, "L4"), ] def read_json(path, default=None): try: if os.path.exists(path): with open(path, "r") as f: return json.load(f) except: pass return default def write_json(path, data): try: with open(path, "w") as f: json.dump(data, f, indent=2) except Exception as e: print(f"[Capital] Failed to write {path}: {e}", flush=True) def read_file(path, default=""): try: if os.path.exists(path): with open(path, "r") as f: return f.read().strip() except: pass return default def load_state(filepath=STATE_FILE): state = read_json(filepath) if state is None: state = { "tier_index": 0, "consecutive_wins": 0, "consecutive_losses": 0, "risk_pool": DEFAULT_RISK_POOL, "total_capital": DEFAULT_TOTAL_CAPITAL, "max_bet": DEFAULT_RISK_POOL * 0.20, "reinvest_rate": TIERS[0][0], "halted": False, "original_deposit": None, "deposit_date": None, } return state def save_state(state, filepath=STATE_FILE): write_json(filepath, state) def get_risk_ratio(total_capital): if total_capital <= 50: return 0.25 elif total_capital <= 200: return 0.20 elif total_capital <= 1000: return 0.15 elif total_capital <= 5000: return 0.10 else: return 0.08 def update_after_trade(won: bool, profit_amount: float, filepath=STATE_FILE): state = load_state(filepath) if state["original_deposit"] is None and filepath != VIRTUAL_STATE_FILE: bal = read_file(BALANCE_FILE, "0") try: bal = float(bal) except: bal = 0.0 if bal > 0: state["original_deposit"] = bal state["deposit_date"] = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M UTC") state["total_capital"] += profit_amount if won: state["consecutive_wins"] += 1 state["consecutive_losses"] = 0 tier_idx = state["tier_index"] required = TIERS[tier_idx][1] if state["consecutive_wins"] >= required and tier_idx < len(TIERS) - 1: state["tier_index"] = tier_idx + 1 state["consecutive_wins"] = 0 state["reinvest_rate"] = TIERS[state["tier_index"]][0] print(f"[Capital] 🟢 Upgraded to {TIERS[state['tier_index']][2]} " f"({state['reinvest_rate']:.0%} reinvest)", flush=True) reinvest = profit_amount * state["reinvest_rate"] state["risk_pool"] += reinvest else: state["consecutive_losses"] += 1 state["consecutive_wins"] = 0 state["risk_pool"] = max(0.0, state["risk_pool"] + profit_amount) if state["consecutive_losses"] >= 2 and state["tier_index"] > 0: state["tier_index"] -= 1 state["consecutive_wins"] = 0 state["consecutive_losses"] = 0 state["reinvest_rate"] = TIERS[state["tier_index"]][0] print(f"[Capital] 🔴 Downgraded to {TIERS[state['tier_index']][2]} " f"({state['reinvest_rate']:.0%} reinvest)", flush=True) total = state["total_capital"] ratio = get_risk_ratio(total) target_risk_pool = total * ratio if target_risk_pool > state["risk_pool"]: state["risk_pool"] = target_risk_pool elif state["risk_pool"] > target_risk_pool: state["risk_pool"] = target_risk_pool initial_risk = state["original_deposit"] * 0.25 if state["original_deposit"] else DEFAULT_RISK_POOL if state["risk_pool"] < initial_risk * 0.5: state["halted"] = True print("[Capital] ⚠️ CIRCUIT BREAKER TRIGGERED: risk pool < 50% of initial", flush=True) if os.path.exists(HALT_FILE): state["halted"] = True os.remove(HALT_FILE) print("[Capital] ⚠️ Manual HALT triggered", flush=True) if os.path.exists(UNHALT_FILE): state["halted"] = False os.remove(UNHALT_FILE) print("[Capital] ✅ Manual UNHALT — trading resumed", flush=True) state["max_bet"] = round(state["risk_pool"] * 0.20, 2) save_state(state, filepath) return state def get_summary(): state = load_state() tier = TIERS[state["tier_index"]] return { "tier": tier[2], "tier_index": state["tier_index"], "reinvest_rate": state["reinvest_rate"], "consecutive_wins": state["consecutive_wins"], "wins_needed": tier[1], "consecutive_losses": state["consecutive_losses"], "risk_pool": round(state["risk_pool"], 2), "max_bet": round(state["max_bet"], 2), "total_capital": round(state["total_capital"], 2), "halted": state["halted"], "original_deposit": state["original_deposit"], "deposit_date": state["deposit_date"], }