Files
autofirmer-expanded/app/api/firms/route.ts
T
Brandon LiandClaude Opus 5.5 28f465508d DXtrade platform for Tradeify247: percent fees, hard daily-loss stops, volatility sizing, every-day lanes
- DXtrade client (lib/dxtrade-class.ts): REST session login with lockout-safe
  backoff, 60s sync of accounts/metrics/positions/orders/transfers, history and
  fund transactions from cash transactions, day-start balance at the 22:00 UTC
  reset, CLOSE-by-positionCode exits (native OCO group, else a stop-first
  emulated pair), a cross-account hedge guard, stray-order reaper.
- Instrument selector: the firm's symbol map lists candidate symbols per CME
  root; the cheapest tradable one per unit of recent hourly volatility wins
  (spread + 2x commission [+ financing] / sigma).
- Fees: a firm's commission % of notional prices every fee off the fill; the
  take-profit is solved in closed form so the leg nets its target.
- Hard daily loss limit per account type: every leg carries a stop keeping the
  firm's day inside the limit less a 10% reserve and both fees (rounded in);
  a green day never widens it; no room or a refused bracket flattens.
- Notional sizing where the platform prices positions: target-hold volatility
  sizing or the symbol map's fixed notional, under a per-type notional cap.
- Every-day firms trade weekends/holidays; the scheduler runs lanes (futures,
  one per DXtrade firm) with their own hours, flat gate, mutex and batches.
- The catalog sync skips platforms this build doesn't know instead of treating
  them as Tradovate. One shared fireLeg replaces the duplicated batch/copy code.
- npm run check: fee/stop/sizing/hours/selector checks; scripts/dxtrade-smoke.mjs
  confirms the API against a real login before trading.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 16:04:15 -05:00

60 lines
2.4 KiB
TypeScript

import { NextResponse } from 'next/server';
import { getCachedCatalog, hasPlatformCredentials } from '@/lib/firm-catalog';
import { getCredentials } from '@/lib/db';
import type { FirmConfig } from '@/types';
/**
* The firms this machine knows about — the master's catalog, annotated with
* whether credentials for each are stored here.
*
* Firms are created and edited on the master dashboard; there is no POST. The
* only writable thing per firm is its credentials, at
* PUT /api/firms/[id]/credentials.
*
* The stored password is deliberately not returned. It used to be, and nothing
* ever read it.
*/
export async function GET() {
try {
const result: FirmConfig[] = getCachedCatalog().map((firm) => {
const creds = getCredentials(firm.id);
const hasCredentials = hasPlatformCredentials(firm.platform, creds);
return {
id: firm.id,
firm: firm.name,
platform: firm.platform,
username: creds?.username ?? '',
hasCredentials,
bannedSymbols: firm.bannedSymbols,
accounts: firm.accountTypes.map((a) => ({
id: a.id,
label: a.label,
prefix: a.prefix,
profitTarget: a.profitTarget,
consistency: a.consistency,
minDayPnL: a.minDayPnL,
minTradingDays: a.minTradingDays,
accountSize: a.accountSize,
maxLoss: a.maxLoss,
maxPositionSize: a.maxPositionSize,
targetSameEquity: a.targetSameEquity,
splitEnabled: a.splitEnabled,
minLegs: a.minLegs,
firstDayStop: a.firstDayStop,
minDayStop: a.minDayStop,
combineCmeHolidays: a.combineCmeHolidays,
withdrawalStages: a.withdrawalStages,
dailyLossLimit: a.dailyLossLimit ?? 0,
maxNotional: a.maxNotional ?? 0,
tradesEveryDay: a.tradesEveryDay === true,
})),
catalogUpdatedAt: firm.updatedAt,
};
});
return NextResponse.json(result);
} catch (err) {
console.error('[GET /api/firms]', err);
return NextResponse.json({ error: 'Failed to fetch firms' }, { status: 500 });
}
}