Spaces:
Running
Running
Daniel Alnawaz commited on
Capital tracking
Browse files- autonomous_bot.py +38 -5
autonomous_bot.py
CHANGED
|
@@ -497,17 +497,42 @@ class AutonomousTradingBot:
|
|
| 497 |
if paper_mode:
|
| 498 |
logger.info("π PAPER TRADE MODE β no real orders will be placed.")
|
| 499 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 500 |
def get_equity_for(slot: StrategySlot) -> float:
|
| 501 |
if paper_mode:
|
| 502 |
-
|
|
|
|
| 503 |
try:
|
| 504 |
state = self.api.get_user_state(user_addr)
|
| 505 |
ms = state.get("crossMarginSummary") or state.get("marginSummary") or {}
|
| 506 |
real = float(ms.get("accountValue", 0.0))
|
| 507 |
-
|
|
|
|
|
|
|
| 508 |
except Exception as e:
|
| 509 |
logger.error(f"equity fetch error: {e}")
|
| 510 |
-
return
|
| 511 |
|
| 512 |
def get_position(coin: str) -> float:
|
| 513 |
if paper_mode:
|
|
@@ -602,6 +627,12 @@ class AutonomousTradingBot:
|
|
| 602 |
)
|
| 603 |
pnl_usdc = (px - entry_px) * trade_sz * side if trade_sz > 0 else None
|
| 604 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 605 |
self.tg.send_exit(slot.coin, exit_reason, pnl_usdc=pnl_usdc,
|
| 606 |
strategy=slot.strategy_name, timeframe=slot.timeframe)
|
| 607 |
slot.open_trade = None
|
|
@@ -827,11 +858,13 @@ class AutonomousTradingBot:
|
|
| 827 |
subscribe_all()
|
| 828 |
|
| 829 |
slot_summary = ", ".join(f"{s.coin}/{s.timeframe}({s.strategy_name})" for s in self.slots)
|
|
|
|
| 830 |
self.tg.send_info(
|
| 831 |
f"π€ *Bot started* β account `{user_addr}`\n"
|
| 832 |
f"Slots: `{slot_summary}`\n"
|
| 833 |
-
f"Capital: ${max_cap:.2f} | Leverage: {leverage}x | "
|
| 834 |
-
f"{'π PAPER' if paper_mode else 'π° LIVE'}"
|
|
|
|
| 835 |
)
|
| 836 |
|
| 837 |
logger.info(f"Running {len(self.slots)} slot(s): " +
|
|
|
|
| 497 |
if paper_mode:
|
| 498 |
logger.info("π PAPER TRADE MODE β no real orders will be placed.")
|
| 499 |
|
| 500 |
+
# ββ Compounding capital tracker βββββββββββββββββββββββββββββββ
|
| 501 |
+
# Tracks each slot's running capital in memory.
|
| 502 |
+
# - Paper mode: starts at max_cap * capital_frac, updated after every
|
| 503 |
+
# closed trade so profits/losses compound into position sizing.
|
| 504 |
+
# - Live mode: reads real on-chain equity (already compounds naturally),
|
| 505 |
+
# scaled by this slot's fraction of total capital. No hard ceiling so
|
| 506 |
+
# gains are not lost.
|
| 507 |
+
_running_capital: Dict[str, float] = {
|
| 508 |
+
slot.label: max_cap * slot.capital_frac for slot in self.slots
|
| 509 |
+
}
|
| 510 |
+
|
| 511 |
+
def _update_running_capital(slot: StrategySlot, pnl: float):
|
| 512 |
+
"""Apply a closed-trade PnL to the slot's running capital."""
|
| 513 |
+
old = _running_capital[slot.label]
|
| 514 |
+
_running_capital[slot.label] = max(old + pnl, 1.0) # floor at $1 to avoid sizing to 0
|
| 515 |
+
new = _running_capital[slot.label]
|
| 516 |
+
change = "π" if pnl >= 0 else "π"
|
| 517 |
+
logger.info(
|
| 518 |
+
f"{slot.label} {change} capital updated: "
|
| 519 |
+
f"${old:.2f} β ${new:.2f} (PnL {pnl:+.4f} USDC)"
|
| 520 |
+
)
|
| 521 |
+
|
| 522 |
def get_equity_for(slot: StrategySlot) -> float:
|
| 523 |
if paper_mode:
|
| 524 |
+
# Paper: use compounding in-memory capital
|
| 525 |
+
return _running_capital[slot.label]
|
| 526 |
try:
|
| 527 |
state = self.api.get_user_state(user_addr)
|
| 528 |
ms = state.get("crossMarginSummary") or state.get("marginSummary") or {}
|
| 529 |
real = float(ms.get("accountValue", 0.0))
|
| 530 |
+
# Scale total equity by this slot's capital fraction.
|
| 531 |
+
# No hard ceiling β profits compound naturally.
|
| 532 |
+
return real * slot.capital_frac
|
| 533 |
except Exception as e:
|
| 534 |
logger.error(f"equity fetch error: {e}")
|
| 535 |
+
return _running_capital[slot.label] # fall back to last known value
|
| 536 |
|
| 537 |
def get_position(coin: str) -> float:
|
| 538 |
if paper_mode:
|
|
|
|
| 627 |
)
|
| 628 |
pnl_usdc = (px - entry_px) * trade_sz * side if trade_sz > 0 else None
|
| 629 |
|
| 630 |
+
# ββ Compound capital ββββββββββββββββββββββββββββββ
|
| 631 |
+
# Update slot's running capital so next position is
|
| 632 |
+
# sized from the new (grown or shrunk) equity.
|
| 633 |
+
if pnl_usdc is not None:
|
| 634 |
+
_update_running_capital(slot, pnl_usdc)
|
| 635 |
+
|
| 636 |
self.tg.send_exit(slot.coin, exit_reason, pnl_usdc=pnl_usdc,
|
| 637 |
strategy=slot.strategy_name, timeframe=slot.timeframe)
|
| 638 |
slot.open_trade = None
|
|
|
|
| 858 |
subscribe_all()
|
| 859 |
|
| 860 |
slot_summary = ", ".join(f"{s.coin}/{s.timeframe}({s.strategy_name})" for s in self.slots)
|
| 861 |
+
capital_summary = " | ".join(f"{s.label}=${_running_capital[s.label]:.2f}" for s in self.slots)
|
| 862 |
self.tg.send_info(
|
| 863 |
f"π€ *Bot started* β account `{user_addr}`\n"
|
| 864 |
f"Slots: `{slot_summary}`\n"
|
| 865 |
+
f"Capital: ${max_cap:.2f} total | Leverage: {leverage}x | "
|
| 866 |
+
f"{'π PAPER' if paper_mode else 'π° LIVE'}\n"
|
| 867 |
+
f"Per-slot: `{capital_summary}`"
|
| 868 |
)
|
| 869 |
|
| 870 |
logger.info(f"Running {len(self.slots)} slot(s): " +
|