Files
autofirmer-expanded/app/settings/page.tsx
T
SenofyandClaude Sonnet 4.6 dd18f91584 Add full Next.js autotrader app with SQLite persistence and live Tradovate data
- SQLite DB (better-sqlite3) with firms, account_configs, firm_fees, instruments tables
- REST API routes: firms CRUD, account configs CRUD, state, accounts, instruments
- Live Tradovate WebSocket client: login, sync, positions, auto-liq thresholds
- Dashboard (app/page.tsx): per-firm account list with balance, day P&L, days traded,
  target progress, and Dead/Inactive/Flat status based on Tradovate auto-liq floors
- Account detail page: objectives progress, daily P&L chart, consistency tracking
- Per-firm settings page: account configs and instrument fee management
- Dead detection uses trailingMaxDrawdownLimit - trailingMaxDrawdown from
  userAccountAutoLiqs; filters Tradovate sentinel value (999999999 = no limit)
- FIFO P&L engine with commission accounting for daily P&L history
- Removed manual maxLoss fallback in favour of live Tradovate auto-liq data

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-08 15:03:21 -05:00

90 lines
4.0 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import Link from 'next/link';
interface Instrument {
symbol: string;
enabled: boolean;
}
export default function SettingsPage() {
const [instruments, setInstruments] = useState<Instrument[]>([]);
useEffect(() => {
fetch('/api/instruments')
.then((r) => r.json())
.then(setInstruments);
}, []);
async function toggle(symbol: string, enabled: boolean) {
setInstruments((prev) =>
prev.map((i) => (i.symbol === symbol ? { ...i, enabled } : i))
);
await fetch(`/api/instruments/${symbol}`, {
method: 'PATCH',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ enabled }),
});
}
return (
<div className="min-h-screen bg-slate-50 p-8">
<div className="max-w-7xl mx-auto">
<div className="flex items-center gap-3 mb-6">
<Link
href="/"
className="text-slate-400 hover:text-slate-600 text-sm transition-colors"
>
Back
</Link>
<h1 className="text-2xl font-bold text-slate-900">Settings</h1>
</div>
<h2 className="text-sm font-semibold uppercase tracking-wider text-slate-500 mb-3">
Instruments
</h2>
<div className="bg-white border border-slate-200 rounded-xl overflow-hidden shadow-sm">
{instruments.length === 0 ? (
<div className="px-4 py-8 text-center text-sm text-slate-400 italic">
Loading
</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-right text-xs font-semibold uppercase tracking-wider text-slate-400">Enabled</th>
</tr>
</thead>
<tbody>
{instruments.map((instr) => (
<tr key={instr.symbol} className="border-b border-slate-100 last:border-0">
<td className="px-4 py-2.5 font-mono font-semibold text-slate-800">{instr.symbol}</td>
<td className="px-4 py-2.5 text-right">
<button
onClick={() => toggle(instr.symbol, !instr.enabled)}
className={`relative inline-flex h-5 w-9 items-center rounded-full transition-colors focus:outline-none ${
instr.enabled ? 'bg-blue-500' : 'bg-slate-200'
}`}
>
<span
className={`inline-block h-3.5 w-3.5 transform rounded-full bg-white shadow transition-transform ${
instr.enabled ? 'translate-x-4' : 'translate-x-1'
}`}
/>
</button>
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
</div>
);
}