PINK: seed capital from BingX ledger of record on startup
Previously: set_seed_capital(hardcoded_25000) then on_account_event(BingX_100K+) → reconcile delta ~75K → capital_frozen=True → no trades allowed. Fix: _fetch_exchange_wallet_balance() queries BingX wallet balance BEFORE seeding the kernel. set_seed_capital() and the subsequent ACCOUNT_UPDATE reconcile now agree → delta ≈ 0 → capital_frozen=False → sizing correct. Falls back to DOLPHIN_INITIAL_CAPITAL if BingX is unreachable, with WARNING. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -296,12 +296,15 @@ class PinkDirectRuntime:
|
||||
await result
|
||||
except Exception as exc:
|
||||
self.logger.warning("Venue connect failed: %s", exc)
|
||||
_reconcile_position_slot(self.kernel, initial_capital, slot_id=0)
|
||||
# BingX is the ledger of record. Fetch wallet balance BEFORE seeding
|
||||
# the kernel so set_seed_capital() and reconcile agree with the exchange.
|
||||
# Using a hardcoded fallback (e.g. 25000) while the VST account holds
|
||||
# 100K+ would cause a ~75K reconcile delta → capital_frozen=True.
|
||||
live_capital = await self._fetch_exchange_wallet_balance(initial_capital)
|
||||
_reconcile_position_slot(self.kernel, live_capital, slot_id=0)
|
||||
|
||||
# Seed the kernel's atomic K-account from exchange truth.
|
||||
# This is the crash/restart recovery point: if the kernel restarted
|
||||
# it re-reads exchange state here before accepting any ENTERs.
|
||||
self.kernel.set_seed_capital(initial_capital)
|
||||
self.kernel.set_seed_capital(live_capital)
|
||||
await self._seed_account_from_exchange()
|
||||
|
||||
# Restore fee calibration + account state from the previous session if the
|
||||
@@ -340,6 +343,46 @@ class PinkDirectRuntime:
|
||||
"funding_interval_secs": 28_800, # 8 h BingX perps
|
||||
})
|
||||
|
||||
async def _fetch_exchange_wallet_balance(self, fallback: float) -> float:
|
||||
"""Query BingX for the current wallet balance to use as the capital seed.
|
||||
|
||||
BingX VST (and live) is the ledger of record. Seeding the kernel from
|
||||
a hardcoded constant while the exchange holds a different balance causes
|
||||
a large reconcile delta → capital_frozen=True on every startup.
|
||||
|
||||
Falls back to *fallback* if the HTTP client is unavailable or the
|
||||
request fails, logging a WARNING so operators know sizing is approximate.
|
||||
"""
|
||||
http_client = self._venue_http_client()
|
||||
if http_client is None:
|
||||
self.logger.warning(
|
||||
"No HTTP client — capital seeded from fallback=%.2f (BingX unreachable)",
|
||||
fallback,
|
||||
)
|
||||
return fallback
|
||||
try:
|
||||
from prod.clean_arch.dita_v2.bingx_user_stream import BingxUserStream
|
||||
stream = BingxUserStream(http_client=http_client, ws_base_url="")
|
||||
ev = await stream.account_snapshot()
|
||||
balance = float(ev.wallet_balance or 0.0)
|
||||
if balance <= 0:
|
||||
self.logger.warning(
|
||||
"BingX returned wallet_balance=%.2f ≤ 0 — using fallback=%.2f",
|
||||
balance, fallback,
|
||||
)
|
||||
return fallback
|
||||
self.logger.info(
|
||||
"Capital seeded from BingX ledger: wallet=%.2f (fallback was %.2f)",
|
||||
balance, fallback,
|
||||
)
|
||||
return balance
|
||||
except Exception as exc:
|
||||
self.logger.warning(
|
||||
"BingX wallet fetch failed (%s) — capital seeded from fallback=%.2f",
|
||||
exc, fallback,
|
||||
)
|
||||
return fallback
|
||||
|
||||
async def _seed_account_from_exchange(self) -> None:
|
||||
"""
|
||||
Startup/crash-recovery:
|
||||
|
||||
Reference in New Issue
Block a user