Add auto-trade scheduler with batch locking, commission gross-up, and sync gate
- Auto-trade scheduler fires every 60s; uses Promise.allSettled batch so no new trades fire while any position from the current batch is open
- Commission gross-up: read entryCommission from cash.realizedPnL after fill (fallback 2.5×contracts), grossTarget = target + 2×entryCommission
- Sync gate: TradovateClient.syncComplete flag; scheduler skips tick until every client finishes initial position/balance sync
- Contracts formula changed to Math.ceil so $1500 target = 2 contracts
- Removed all fee caching (perContractFees, recentFills, fillFee handler) from tradovate-class.ts
- Removed firm_fees table, getFirmFees, upsertFirmFee from db.ts
- Deleted instrument-configs API routes; removed Fees UI from firm settings page
- /api/instruments returns full {symbol, enabled}[] objects; dashboard filters to enabled-only for trade selector
- Added auto-trade, debug, orders, settings, and trade API routes
- Instrument selector on dashboard now driven by enabled instruments from DB
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
532c2e2279
commit
b2a1bdd1c3
@@ -23,14 +23,6 @@ db.exec(`
|
||||
min_trading_days INTEGER NOT NULL DEFAULT 5
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS firm_fees (
|
||||
firm_id INTEGER NOT NULL REFERENCES firms(id) ON DELETE CASCADE,
|
||||
symbol TEXT NOT NULL,
|
||||
allin_fee REAL NOT NULL DEFAULT 0,
|
||||
roundtrip_fee REAL NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (firm_id, symbol)
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS instruments (
|
||||
symbol TEXT PRIMARY KEY,
|
||||
enabled INTEGER NOT NULL DEFAULT 1
|
||||
@@ -98,13 +90,6 @@ export interface FirmWithAccounts extends FirmRow {
|
||||
accounts: AccountConfigRow[];
|
||||
}
|
||||
|
||||
export interface FirmFee {
|
||||
firmId: number;
|
||||
symbol: string;
|
||||
allinFee: number;
|
||||
roundtripFee: number;
|
||||
}
|
||||
|
||||
// ── Firms ───────────────────────────────────────────────────────────────────
|
||||
|
||||
export function getFirms(): FirmWithAccounts[] {
|
||||
@@ -174,30 +159,26 @@ export function updateAccountConfig(id: number, data: {
|
||||
return result.changes > 0;
|
||||
}
|
||||
|
||||
// ── Firm Fees ────────────────────────────────────────────────────────────────
|
||||
// ── Settings ─────────────────────────────────────────────────────────────────
|
||||
|
||||
export function getFirmFees(firmId: number): FirmFee[] {
|
||||
return (db.prepare('SELECT firm_id, symbol, allin_fee, roundtrip_fee FROM firm_fees WHERE firm_id = ? ORDER BY symbol').all(firmId) as {
|
||||
firm_id: number;
|
||||
symbol: string;
|
||||
allin_fee: number;
|
||||
roundtrip_fee: number;
|
||||
}[]).map((r) => ({
|
||||
firmId: r.firm_id,
|
||||
symbol: r.symbol,
|
||||
allinFee: r.allin_fee,
|
||||
roundtripFee: r.roundtrip_fee,
|
||||
}));
|
||||
db.exec(`
|
||||
CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT NOT NULL
|
||||
);
|
||||
`);
|
||||
|
||||
// Seed defaults if missing
|
||||
const seedSetting = db.prepare(`INSERT OR IGNORE INTO settings (key, value) VALUES (?, ?)`);
|
||||
seedSetting.run('max_concurrent_accounts', '5');
|
||||
|
||||
export function getSetting(key: string): string | null {
|
||||
const row = db.prepare('SELECT value FROM settings WHERE key = ?').get(key) as { value: string } | undefined;
|
||||
return row?.value ?? null;
|
||||
}
|
||||
|
||||
export function upsertFirmFee(firmId: number, symbol: string, allinFee: number, roundtripFee: number): void {
|
||||
db.prepare(`
|
||||
INSERT INTO firm_fees (firm_id, symbol, allin_fee, roundtrip_fee)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(firm_id, symbol) DO UPDATE SET
|
||||
allin_fee = excluded.allin_fee,
|
||||
roundtrip_fee = excluded.roundtrip_fee
|
||||
`).run(firmId, symbol, allinFee, roundtripFee);
|
||||
export function setSetting(key: string, value: string): void {
|
||||
db.prepare(`INSERT INTO settings (key, value) VALUES (?, ?) ON CONFLICT(key) DO UPDATE SET value = excluded.value`).run(key, value);
|
||||
}
|
||||
|
||||
// ── Instruments ──────────────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user