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
@@ -8,13 +8,28 @@ interface Instrument {
|
||||
enabled: boolean;
|
||||
}
|
||||
|
||||
interface AppSettings {
|
||||
max_concurrent_accounts: string | null;
|
||||
}
|
||||
|
||||
export default function SettingsPage() {
|
||||
const [instruments, setInstruments] = useState<Instrument[]>([]);
|
||||
const [maxConcurrent, setMaxConcurrent] = useState<string>('5');
|
||||
const [saving, setSaving] = useState(false);
|
||||
const [saved, setSaved] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
fetch('/api/instruments')
|
||||
.then((r) => r.json())
|
||||
.then(setInstruments);
|
||||
|
||||
fetch('/api/settings')
|
||||
.then((r) => r.json())
|
||||
.then((s: AppSettings) => {
|
||||
if (s.max_concurrent_accounts != null) {
|
||||
setMaxConcurrent(s.max_concurrent_accounts);
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
|
||||
async function toggle(symbol: string, enabled: boolean) {
|
||||
@@ -28,6 +43,19 @@ export default function SettingsPage() {
|
||||
});
|
||||
}
|
||||
|
||||
async function saveSettings() {
|
||||
setSaving(true);
|
||||
setSaved(false);
|
||||
await fetch('/api/settings', {
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ max_concurrent_accounts: maxConcurrent }),
|
||||
});
|
||||
setSaving(false);
|
||||
setSaved(true);
|
||||
setTimeout(() => setSaved(false), 2000);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-slate-50 p-8">
|
||||
<div className="max-w-7xl mx-auto">
|
||||
@@ -42,6 +70,43 @@ export default function SettingsPage() {
|
||||
<h1 className="text-2xl font-bold text-slate-900">Settings</h1>
|
||||
</div>
|
||||
|
||||
{/* ── Trading ── */}
|
||||
<h2 className="text-sm font-semibold uppercase tracking-wider text-slate-500 mb-3">
|
||||
Trading
|
||||
</h2>
|
||||
<div className="bg-white border border-slate-200 rounded-xl shadow-sm mb-8">
|
||||
<div className="flex items-center justify-between px-4 py-3">
|
||||
<div>
|
||||
<p className="text-sm font-medium text-slate-800">Max concurrent accounts</p>
|
||||
<p className="text-xs text-slate-400 mt-0.5">
|
||||
How many accounts trade in parallel per /api/trade call
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-3">
|
||||
<input
|
||||
type="number"
|
||||
min={1}
|
||||
max={500}
|
||||
value={maxConcurrent}
|
||||
onChange={(e) => setMaxConcurrent(e.target.value)}
|
||||
className="w-20 rounded-lg border border-slate-200 bg-slate-50 px-3 py-1.5 text-sm text-right font-mono text-slate-800 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<button
|
||||
onClick={saveSettings}
|
||||
disabled={saving}
|
||||
className={`text-sm px-3 py-1.5 rounded-lg font-medium transition-colors ${
|
||||
saved
|
||||
? 'bg-green-500 text-white'
|
||||
: 'bg-blue-500 hover:bg-blue-600 text-white disabled:opacity-50'
|
||||
}`}
|
||||
>
|
||||
{saved ? 'Saved ✓' : saving ? 'Saving…' : 'Save'}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* ── Instruments ── */}
|
||||
<h2 className="text-sm font-semibold uppercase tracking-wider text-slate-500 mb-3">
|
||||
Instruments
|
||||
</h2>
|
||||
|
||||
Reference in New Issue
Block a user