Reconstruct TopstepX MLL floors from the EOD balance curve
TopstepX never reports the Maximum Loss Limit, but it's deterministic: floor = min(0, eodBalanceHigh − trailingDrawdown), locking at the $0 starting balance. The EOD curve rebuilds from daily P&L + fund events, with off-book fee drift spread across days proportionally to reported fees (validated against a platform-reported MLL to ~$0.10). Stored in autoLiqThresholds — negative, or +$0.01 once locked — so dead detection, dashboards, and the ruin model's startThreshold all use the real room. Guards move from '> 0' to '!== 0'; 0 still means no floor. canTrade=false accounts are skipped. daily_pnl gains a fees column for the weighting. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4edb771701
commit
fc65b4340d
@@ -236,18 +236,27 @@ db.exec(`
|
||||
);
|
||||
`);
|
||||
|
||||
export function saveDailyPnL(accountId: number, accountName: string, entries: { date: string; pnl: number }[]): void {
|
||||
const ins = db.prepare('INSERT OR REPLACE INTO daily_pnl (account_id, account_name, date, pnl) VALUES (?, ?, ?, ?)');
|
||||
// Migration: the day's reported fees (TopstepX). The MLL reconstruction
|
||||
// distributes off-book fee drift across days proportionally to these; rows
|
||||
// from before the migration read 0 until the next fetch overwrites them.
|
||||
try {
|
||||
db.exec('ALTER TABLE daily_pnl ADD COLUMN fees REAL NOT NULL DEFAULT 0');
|
||||
} catch {
|
||||
// Column already exists
|
||||
}
|
||||
|
||||
export function saveDailyPnL(accountId: number, accountName: string, entries: { date: string; pnl: number; fees?: number }[]): void {
|
||||
const ins = db.prepare('INSERT OR REPLACE INTO daily_pnl (account_id, account_name, date, pnl, fees) VALUES (?, ?, ?, ?, ?)');
|
||||
const txn = db.transaction(() => {
|
||||
for (const e of entries) {
|
||||
ins.run(accountId, accountName, e.date, e.pnl);
|
||||
ins.run(accountId, accountName, e.date, e.pnl, e.fees ?? 0);
|
||||
}
|
||||
});
|
||||
txn();
|
||||
}
|
||||
|
||||
export function loadDailyPnL(accountId: number): { date: string; pnl: number }[] {
|
||||
return (db.prepare('SELECT date, pnl FROM daily_pnl WHERE account_id = ? ORDER BY date').all(accountId) as { date: string; pnl: number }[]);
|
||||
export function loadDailyPnL(accountId: number): { date: string; pnl: number; fees: number }[] {
|
||||
return (db.prepare('SELECT date, pnl, fees FROM daily_pnl WHERE account_id = ? ORDER BY date').all(accountId) as { date: string; pnl: number; fees: number }[]);
|
||||
}
|
||||
|
||||
// ── Fund Transactions Cache ───────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user