Appearance
MonitoringManager
This manager is not expected to work in production. A 30-second polling interval for MLL breach detection means there is a 30-second window where a funded account can lose real money before the system reacts. This design is fundamentally unsuitable for protecting real capital. An event-driven approach (e.g., exchange-side stop-loss, WebSocket price stream with instant evaluation) is required before this can be trusted with real funds.
Alarm-driven MLL monitoring and winning day tracking for all active funded trading accounts.
High-Level Design
Core Loop
MonitoringManager runs a simple poll-check-act loop on a 30-second alarm cycle:
Every 30 seconds:
┌─────────────────────────────────────────┐
│ 1. Query all active master accounts │
│ 2. For each account: │
│ ├─ Delegate health check to │
│ │ MasterAccountManager │
│ │ (fetches live Hyperliquid state) │
│ ├─ If breached → deactivate account │
│ │ (close positions, revoke agents, │
│ │ recycle funds) │
│ └─ If day boundary crossed → │
│ update winning day counter │
│ 3. Schedule next alarm (30s) │
└─────────────────────────────────────────┘The alarm is self-rescheduling — it always sets the next 30s alarm at the end of processAlarm(), even if errors occurred during processing.
Breach Detection
Health checks are fully delegated to MasterAccountManager.checkAccountHealth(), which queries the Hyperliquid clearinghouse API for live account state. MonitoringManager only acts on the result:
- Healthy → continue to day boundary check
- Breached → call
MasterAccountManager.deactivateMasterAccount()which closes all positions, cancels orders, revokes agent accounts, and recycles funds
Each account is monitored independently — an error in one account is caught and logged without blocking others.
Winning Day Tracking
At UTC day boundaries (detected by comparing UTC midnight timestamps), the manager evaluates whether the previous day was a "winning day":
dayProfit = currentAccountValue - propDayStartBalance
if dayProfit >= targetProfitWinningDay:
increment prop_winning_days
Always: update prop_day_start_balance to current valueWinning days feed into payout eligibility — users need a minimum number of winning days before they can request payouts.
On-Demand Health Queries
Beyond the alarm loop, MonitoringManager exposes getAccountHealth() for on-demand queries. This calculates:
- Risk level based on buffer ratio
(accountValue - mllThreshold) / mllThreshold:>20%→ low,>10%→ medium,>0%→ high,≤0%→ critical
- Payout eligibility: healthy + sufficient buffer above safety net + minimum winning days met
Why This Doesn't Work
The 30-second polling interval creates an unacceptable gap for real money:
- Worst case: A flash crash can wipe an account in <1 second. A 30-second poll means the system won't even notice until the next cycle.
- Sequential processing: Accounts are checked one-by-one in a loop. With many active accounts, the effective check interval per account is
30s + (N × API_latency). - Single point of failure: The entire monitoring system lives in one DO. If the alarm misses a cycle (DO eviction, runtime error), all accounts are unprotected.
- No price-driven trigger: The system polls on a timer regardless of market conditions. A sudden price movement doesn't trigger an immediate check.
See Also
- MasterAccountManager - Health checks and deactivation logic
- PayoutManager - Uses winning days and health data for payout eligibility