Files
autofirmer-expanded/app/api/instruments/contracts/route.ts
T
SenofyandClaude Sonnet 4.6 d945e0038f Add volume-based contract auto-resolver and CLAUDE.md
- New lib/contract-resolver.ts: picks the best contract month for each
  symbol by comparing Yahoo Finance volume between the front month
  (Tradovate suggest API) and the roll target (rollcontract API)
- lib/clients.ts: auto-resolves all enabled instruments 15s after startup
  and again daily at midnight via a setInterval check
- lib/tradovate-class.ts: findFrontMonthContract checks resolver cache
  first before falling back to the suggest API
- app/api/instruments/contracts/route.ts: GET returns cached contracts,
  POST triggers a fresh resolve
- app/settings/page.tsx: shows active contract + rolled badge per symbol;
  auto-resolves on load if cache is empty; removed manual Resolve button
- app/api/debug/route.ts: include entity data in recentEntityEvents
- CLAUDE.md: instructs Claude to always work on main

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-12 03:17:09 -05:00

42 lines
1.5 KiB
TypeScript

import { NextResponse } from 'next/server';
import { getClients } from '@/lib/clients';
import { getInstruments } from '@/lib/db';
import { resolveContracts, getAllCachedContracts } from '@/lib/contract-resolver';
/**
* GET /api/instruments/contracts
* Returns cached resolved contracts (fast, no external calls).
*/
export async function GET() {
return NextResponse.json(getAllCachedContracts());
}
/**
* POST /api/instruments/contracts
* Triggers a fresh resolve of all enabled instruments via Tradovate + yfinance.
* Returns the resolved contracts with volume data.
*/
export async function POST() {
try {
const clients = getClients();
// Find first client with a valid token
let accessToken: string | null = null;
for (const [, c] of clients) {
const token = (c as any).accessInfo?.accessToken;
if (token) { accessToken = token; break; }
}
if (!accessToken) {
return NextResponse.json({ error: 'No authenticated client available' }, { status: 503 });
}
const instruments = getInstruments().filter((i) => i.enabled);
const symbols = instruments.map((i) => i.symbol);
const resolved = await resolveContracts(symbols, accessToken);
return NextResponse.json(resolved);
} catch (err: any) {
console.error('[POST /api/instruments/contracts]', err);
return NextResponse.json({ error: err?.message ?? 'Resolve failed' }, { status: 500 });
}
}