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
@@ -5,13 +5,6 @@ import { useRouter, useParams } from 'next/navigation';
|
||||
|
||||
const SIZE_PRESETS = [5_000, 10_000, 25_000, 50_000, 75_000, 100_000, 150_000];
|
||||
|
||||
interface FirmFee {
|
||||
firmId: number;
|
||||
symbol: string;
|
||||
allinFee: number;
|
||||
roundtripFee: number;
|
||||
}
|
||||
|
||||
interface AccountConfig {
|
||||
id: number;
|
||||
prefix: string;
|
||||
@@ -89,7 +82,6 @@ export default function FirmSettingsPage() {
|
||||
|
||||
const [firmName, setFirmName] = useState('');
|
||||
const [rows, setRows] = useState<RowState[]>([]);
|
||||
const [fees, setFees] = useState<FirmFee[]>([]);
|
||||
const [loadError, setLoadError] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
@@ -103,11 +95,6 @@ export default function FirmSettingsPage() {
|
||||
setRows(firm.accounts.map(initRow));
|
||||
})
|
||||
.catch(() => setLoadError('Failed to load firm'));
|
||||
|
||||
fetch(`/api/firms/${id}/instrument-configs`)
|
||||
.then((r) => r.json() as Promise<FirmFee[]>)
|
||||
.then(setFees)
|
||||
.catch(() => {});
|
||||
}, [id]);
|
||||
|
||||
const updateRow = (rowId: number, patch: Partial<RowState>) => {
|
||||
@@ -428,37 +415,6 @@ export default function FirmSettingsPage() {
|
||||
</table>
|
||||
</div>
|
||||
|
||||
{/* Fees */}
|
||||
<h2 className="text-sm font-semibold uppercase tracking-wider text-slate-500 mt-8 mb-3">
|
||||
Fees
|
||||
</h2>
|
||||
<div className="bg-white border border-slate-200 rounded-xl overflow-hidden shadow-sm">
|
||||
{fees.length === 0 ? (
|
||||
<div className="px-4 py-8 text-center text-sm text-slate-400 italic">
|
||||
No fees loaded yet
|
||||
</div>
|
||||
) : (
|
||||
<table className="w-full text-sm border-collapse">
|
||||
<thead>
|
||||
<tr className="border-b border-slate-200 bg-slate-50">
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-slate-400">Symbol</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-slate-400">All-In Fee</th>
|
||||
<th className="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wider text-slate-400">Roundtrip Fee</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{fees.map((fee) => (
|
||||
<tr key={fee.symbol} className="border-b border-slate-100 last:border-0">
|
||||
<td className="px-4 py-2.5 font-mono font-semibold text-slate-800">{fee.symbol}</td>
|
||||
<td className="px-4 py-2.5 font-mono text-slate-600">${fee.allinFee.toFixed(4)}</td>
|
||||
<td className="px-4 py-2.5 font-mono text-slate-600">${fee.roundtripFee.toFixed(4)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
)}
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user