- Transfers: a close books its SETTLEMENT and COMMISSION under one transaction code, and keying by the code alone let the commission overwrite the P&L. Keys now carry the type, so the day-start balance, daily-loss room, realized P&L, daily history and books check all see closed-trade profit and loss. - Volatility from a week of hourly closes (was 48 h), still measured once per trade date, so one quiet weekend can't triple a hold estimate. - Each symbol's margin rate from the account's instrument details caps the position at available funds / rate (Tradeify: 5:1 crypto, 2:1 stocks); the account type's max notional stays as an optional ceiling. - Firms with overnight financing add the swap a winning leg is expected to pay (the winners' mean hold, (A²+2AB)/3σ²) to its take-profit, and the sizing and hold estimate count it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
139 lines
7.0 KiB
TypeScript
139 lines
7.0 KiB
TypeScript
import type { FirmPlatform } from './lib/master-protocol';
|
|
|
|
export interface AccountConfig {
|
|
/** Master's account type id — what a manual assignment pins to. */
|
|
id: string;
|
|
label: string;
|
|
prefix: string;
|
|
profitTarget: number;
|
|
consistency: number;
|
|
minDayPnL: number;
|
|
minTradingDays: number;
|
|
accountSize: number;
|
|
maxLoss: number; // 0 = no limit; positive = account is "Dead" when loss exceeds this
|
|
maxPositionSize: number; // 0 = no limit; positive = max contracts per trade
|
|
targetSameEquity: boolean; // if true, reduce profitTarget by priorProfit after withdrawal
|
|
splitEnabled: boolean; // false = big days trade as one unsplit leg instead of random ≥$500 pieces
|
|
minLegs: number; // big days (> $1,700) must carve at least this many legs (0 = however the carve falls)
|
|
firstDayStop: boolean; // first cycle day carries a $1,000 account stop - books red and ends
|
|
minDayStop: boolean; // min-day trades carry a 2x-target stop; next day after a loss rides stopless
|
|
combineCmeHolidays: boolean; // true = CME holiday sessions count with the next full trading day (Apex-style)
|
|
withdrawalStages: { profit: number; consistency: number; minTradingDays: number; drain?: boolean; minDayPnL?: number; withdrawalPct?: number; payoutCap?: number }[]; // per-stage fresh profit + consistency (empty = use base values); drain = spam-withdraw stage
|
|
/** Payout model, from the master's payout settings (absent on old masters):
|
|
* withdraw withdrawalPct of balance (capped at payoutCap) per cycle,
|
|
* receive profitSplit of the gross; trailingDrawdown feeds the ruin
|
|
* probabilities. payoutable=false means completing the target just
|
|
* PASSES the account (an eval) rather than paying out. */
|
|
payoutable?: boolean;
|
|
withdrawalPct?: number;
|
|
payoutCap?: number;
|
|
profitSplit?: number;
|
|
trailingDrawdown?: number;
|
|
/** Hard daily loss limit in dollars (0/absent = none): every leg carries a
|
|
* stop that keeps the firm's day inside it, less a 10% reserve and fees. */
|
|
dailyLossLimit?: number;
|
|
/** Cap on one position's notional in dollars (0/absent = none). */
|
|
maxNotional?: number;
|
|
/** The firm trades every calendar day, weekends and CME holidays included. */
|
|
tradesEveryDay?: boolean;
|
|
}
|
|
|
|
export interface FirmConfig {
|
|
/** Master's firm id (uuid). */
|
|
id: string;
|
|
firm: string;
|
|
/** Which platform the firm's accounts trade on — decides both which client
|
|
* drives it and which credential fields the dashboard asks for. */
|
|
platform: FirmPlatform;
|
|
/** Blank when this machine has no credentials for the firm. */
|
|
username: string;
|
|
/** True once the platform's credentials are stored locally — a username +
|
|
* password (Tradovate, DXTrade) or a TopstepX API key. Firms without them
|
|
* are shown greyed out with an inline credential form. */
|
|
hasCredentials: boolean;
|
|
bannedSymbols: string[];
|
|
/** The firm's account types, straight from the catalog. Doubles as the
|
|
* option list for a manual account-type override. */
|
|
accounts: AccountConfig[];
|
|
catalogUpdatedAt: string;
|
|
}
|
|
|
|
export interface AccountState {
|
|
id: number;
|
|
name: string;
|
|
active: boolean;
|
|
amount: number;
|
|
realizedPnL: number;
|
|
daysTraded: number;
|
|
positionDirection: 'long' | 'short' | null;
|
|
/** Balance floor from Tradovate's auto-liquidation profile (0 = not set) */
|
|
autoLiqThreshold: number;
|
|
/** Sum of all historical daily P&L entries */
|
|
totalProfit: number;
|
|
/** True when today's realizedPnL has met or exceeded the computed daily target */
|
|
targetHit: boolean;
|
|
/** True when a stop-enabled account booked its day red via its own stop —
|
|
* the personal DLL. It stands down until the next session's make-back. */
|
|
personalDll: boolean;
|
|
/** True when today's trading finished the current cycle — profit target,
|
|
* consistency and minimum days all met (cycleCompletion 'today'). Only
|
|
* the final day; the firm may lock or remove the account afterwards. */
|
|
completed: boolean;
|
|
/** Current stage = 1 + number of withdrawals (negative fund transactions). Stage 1 = fresh account. */
|
|
stage: number;
|
|
/** True when the current stage is a drain stage (spam-withdraw mode). */
|
|
stageDrain: boolean;
|
|
/** Next trading day's target, computed server-side. null when account is dead or config is missing. */
|
|
dailyTarget: { amount: number; path: 'first_day' | 'normal_day' | 'reduced_day' } | null;
|
|
/** Dollars of price movement the next trade may lose before its stop
|
|
* fires — the tighter of the obfuscation stop and the hard daily-loss
|
|
* stop, before fees. null = the next trade rides stopless (options off,
|
|
* big non-first day, or a make-back day after a loss, with no daily
|
|
* loss limit). */
|
|
nextStop: number | null;
|
|
/** What the firm's day may still lose before a hard daily-loss breach.
|
|
* null = no daily loss limit (or its day-start balance isn't known yet). */
|
|
dllRoom: number | null;
|
|
/** DXtrade: how the next leg would be sized and how long it is expected to
|
|
* hold, from today's measured volatility of the last-picked instrument.
|
|
* null on other platforms, or before the day's first pick. */
|
|
holdEstimate: {
|
|
hours: number;
|
|
symbol: string;
|
|
notional: number;
|
|
volatilityPerDay: number;
|
|
winProbability: number | null;
|
|
/** Expected swap a winning leg pays, added to its take-profit. */
|
|
swapReserve: number;
|
|
/** The broker's leverage on the symbol (5 = 5:1); null when unstated. */
|
|
leverage: number | null;
|
|
} | null;
|
|
/** Actual profit target to hit — max(stage profit target, consistency realTarget = maxDay/consistency). */
|
|
effectiveProfitTarget: number | null;
|
|
/** Current cycle daily P&L — used for target calculations. */
|
|
dailyPnL: { date: string; pnl: number }[];
|
|
/** Full P&L history across all cycles — used for calendar and equity curve display. */
|
|
fullDailyPnL: { date: string; pnl: number }[];
|
|
/** Fund transactions (deposits/withdrawals) — used by the calendar and equity curve. */
|
|
fundTransactions: { date: string; amount: number }[];
|
|
/** Master account type this account resolved to. null = Unassigned. */
|
|
accountTypeId: string | null;
|
|
accountTypeLabel: string | null;
|
|
assignmentSource: 'manual' | 'auto' | 'unassigned';
|
|
/** The resolved config inlined, so client components need no second lookup. */
|
|
accountType: AccountConfig | null;
|
|
/** Size from the initial funding transaction; null until reports return. */
|
|
inferredAccountSize: number | null;
|
|
/** True when more than one account type matched and updatedAt decided it. */
|
|
accountTypeAmbiguous: boolean;
|
|
}
|
|
|
|
export interface FirmState {
|
|
/** Master's firm id — join state to config on this, not on the name, which
|
|
* changes the moment someone renames a firm on the master. */
|
|
firmId: string;
|
|
firm: string;
|
|
connected: boolean;
|
|
accounts: AccountState[];
|
|
}
|