Auto-fetch contract on symbol enable; hide contract when disabled
- POST /api/instruments/contracts now accepts optional { symbols[] } body
to resolve a subset rather than all enabled instruments
- Settings toggle() fires a targeted resolve when enabling a symbol,
merging the result into contracts state without a full page refresh
- Active Contract cell is hidden (null) when the instrument is disabled
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
6d3e8b6065
commit
cade280b2d
@@ -1,4 +1,4 @@
|
|||||||
import { NextResponse } from 'next/server';
|
import { NextRequest, NextResponse } from 'next/server';
|
||||||
import { getClients } from '@/lib/clients';
|
import { getClients } from '@/lib/clients';
|
||||||
import { getInstruments } from '@/lib/db';
|
import { getInstruments } from '@/lib/db';
|
||||||
import { resolveContracts, getAllCachedContracts } from '@/lib/contract-resolver';
|
import { resolveContracts, getAllCachedContracts } from '@/lib/contract-resolver';
|
||||||
@@ -13,10 +13,11 @@ export async function GET() {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* POST /api/instruments/contracts
|
* POST /api/instruments/contracts
|
||||||
* Triggers a fresh resolve of all enabled instruments via Tradovate + yfinance.
|
* Triggers a fresh resolve via Tradovate + Yahoo Finance.
|
||||||
* Returns the resolved contracts with volume data.
|
* Body (optional): { symbols: string[] } — when provided, resolves only those symbols.
|
||||||
|
* Otherwise resolves all enabled instruments.
|
||||||
*/
|
*/
|
||||||
export async function POST() {
|
export async function POST(req: NextRequest) {
|
||||||
try {
|
try {
|
||||||
const clients = getClients();
|
const clients = getClients();
|
||||||
// Find first client with a valid token
|
// Find first client with a valid token
|
||||||
@@ -29,8 +30,12 @@ export async function POST() {
|
|||||||
return NextResponse.json({ error: 'No authenticated client available' }, { status: 503 });
|
return NextResponse.json({ error: 'No authenticated client available' }, { status: 503 });
|
||||||
}
|
}
|
||||||
|
|
||||||
const instruments = getInstruments().filter((i) => i.enabled);
|
const body = await req.json().catch(() => ({}));
|
||||||
const symbols = instruments.map((i) => i.symbol);
|
const requestedSymbols: string[] | undefined = Array.isArray(body?.symbols) ? body.symbols : undefined;
|
||||||
|
|
||||||
|
const symbols = requestedSymbols?.length
|
||||||
|
? requestedSymbols
|
||||||
|
: getInstruments().filter((i) => i.enabled).map((i) => i.symbol);
|
||||||
|
|
||||||
const resolved = await resolveContracts(symbols, accessToken);
|
const resolved = await resolveContracts(symbols, accessToken);
|
||||||
return NextResponse.json(resolved);
|
return NextResponse.json(resolved);
|
||||||
|
|||||||
+18
-4
@@ -67,6 +67,22 @@ export default function SettingsPage() {
|
|||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
body: JSON.stringify({ enabled }),
|
body: JSON.stringify({ enabled }),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// When enabling a symbol, auto-resolve its active contract
|
||||||
|
if (enabled) {
|
||||||
|
fetch('/api/instruments/contracts', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ symbols: [symbol] }),
|
||||||
|
})
|
||||||
|
.then((r) => r.json())
|
||||||
|
.then((fresh: Record<string, ResolvedContract | null>) => {
|
||||||
|
if (!fresh.error) {
|
||||||
|
setContracts((prev) => ({ ...prev, ...fresh }));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function saveSettings() {
|
async function saveSettings() {
|
||||||
@@ -161,7 +177,7 @@ export default function SettingsPage() {
|
|||||||
{instr.symbol}
|
{instr.symbol}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-2.5">
|
<td className="px-4 py-2.5">
|
||||||
{c ? (
|
{instr.enabled && c ? (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span className={`font-mono text-sm ${wasRolled ? 'text-amber-600 font-semibold' : 'text-slate-600'}`}>
|
<span className={`font-mono text-sm ${wasRolled ? 'text-amber-600 font-semibold' : 'text-slate-600'}`}>
|
||||||
{c.name}
|
{c.name}
|
||||||
@@ -177,9 +193,7 @@ export default function SettingsPage() {
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : null}
|
||||||
<span className="text-xs text-slate-300 italic">—</span>
|
|
||||||
)}
|
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-2.5 text-right">
|
<td className="px-4 py-2.5 text-right">
|
||||||
<button
|
<button
|
||||||
|
|||||||
Reference in New Issue
Block a user