- lib/db.ts: new firm_banned_symbols table with getBannedSymbols, isSymbolBanned, and setBannedSymbol helpers - app/api/firms/[id]/banned-symbols/route.ts: GET lists banned symbols, PATCH toggles a ban for a given symbol - app/api/firms/route.ts: include bannedSymbols[] in firm list response - app/firms/[id]/settings/page.tsx: Instruments section shows all globally-enabled symbols with a red toggle to ban/unban; banned symbols display a "SYMBOL BANNED" pill next to their name - app/page.tsx: FirmRows shows "ES BANNED" (or current symbol) pill next to the firm name when the selected trade symbol is banned for that firm - lib/auto-trade.ts: skip firms entirely when the trade symbol is banned - types.ts: add bannedSymbols field to FirmConfig Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
58 lines
2.1 KiB
TypeScript
58 lines
2.1 KiB
TypeScript
import { NextRequest, NextResponse } from 'next/server';
|
|
import { getFirms, createFirm, getBannedSymbols } from '@/lib/db';
|
|
import { initClient } from '@/lib/clients';
|
|
|
|
export async function GET() {
|
|
try {
|
|
const firms = getFirms();
|
|
const result = firms.map((f) => ({
|
|
id: f.id,
|
|
firm: f.name,
|
|
username: f.username,
|
|
password: f.password,
|
|
bannedSymbols: getBannedSymbols(f.id),
|
|
accounts: f.accounts.map((a) => ({
|
|
prefix: a.prefix,
|
|
profitTarget: a.profit_target,
|
|
consistency: a.consistency,
|
|
minDayPnL: a.min_day_pnl,
|
|
minTradingDays: a.min_trading_days,
|
|
accountSize: a.account_size,
|
|
maxLoss: a.max_loss,
|
|
})),
|
|
}));
|
|
return NextResponse.json(result);
|
|
} catch (err) {
|
|
console.error('[GET /api/firms]', err);
|
|
return NextResponse.json({ error: 'Failed to fetch firms' }, { status: 500 });
|
|
}
|
|
}
|
|
|
|
export async function POST(req: NextRequest) {
|
|
const body = await req.json() as { name?: string; username?: string; password?: string };
|
|
const { name, username, password } = body;
|
|
|
|
if (!name?.trim() || !username?.trim() || !password?.trim()) {
|
|
return NextResponse.json({ error: 'name, username, and password are required' }, { status: 400 });
|
|
}
|
|
|
|
try {
|
|
const firm = createFirm(name.trim(), username.trim(), password.trim());
|
|
initClient(firm.id, firm.username, firm.password, firm.name);
|
|
return NextResponse.json({
|
|
id: firm.id,
|
|
firm: firm.name,
|
|
username: firm.username,
|
|
password: firm.password,
|
|
accounts: [],
|
|
}, { status: 201 });
|
|
} catch (err: unknown) {
|
|
const msg = err instanceof Error ? err.message : String(err);
|
|
if (msg.includes('UNIQUE')) {
|
|
return NextResponse.json({ error: 'A firm with that name already exists' }, { status: 409 });
|
|
}
|
|
console.error('[POST /api/firms]', err);
|
|
return NextResponse.json({ error: 'Failed to create firm' }, { status: 500 });
|
|
}
|
|
}
|