Add TopstepX platform support, drain withdrawal stages, and perfect-path calendar projection
- TopstepXClient (ProjectX Gateway): API-key auth, SignalR user hub, Trade/search daily P&L, emulated OCO exits, books-invariant withdrawal detection for $0-start accounts - Platform-aware client pool, credentials (api_key column), and credential form; $0-size account types match by prefix alone - Drain stages: min-day ($5-$15 randomized) MNQ legs for the configured days, then wait for the 50% withdrawal; stage pills show 'Stage N – Drain' - Account calendar projects the perfect path: future days book their planned targets, simulated 50% withdrawals, payout marker Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
1bca441247
commit
50a5eb4713
@@ -0,0 +1,84 @@
|
||||
/**
|
||||
* The surface a platform trading client must expose. TradovateClient grew this
|
||||
* shape organically; TopstepXClient implements the same one so the scheduler,
|
||||
* reporter, state route and resolver can drive either platform without caring
|
||||
* which is behind the map entry.
|
||||
*
|
||||
* Contract ids are `number` on Tradovate and `string` (e.g.
|
||||
* "CON.F.US.ENQ.Z25") on TopstepX — everything that compares them only ever
|
||||
* compares within one client, so the union is safe.
|
||||
*/
|
||||
|
||||
export interface PlatformAccount {
|
||||
id: number;
|
||||
name: string;
|
||||
active: boolean;
|
||||
}
|
||||
|
||||
export interface PlatformContract {
|
||||
id: number | string;
|
||||
name: string;
|
||||
tickSize: number;
|
||||
}
|
||||
|
||||
export interface PlatformClient {
|
||||
accountList: PlatformAccount[];
|
||||
accountCashBalances: { [accountId: number]: { amount: number; realizedPnL: number } };
|
||||
positions: {
|
||||
[accountId: number]: {
|
||||
contractId: number | string;
|
||||
netPos: number;
|
||||
netPrice: number;
|
||||
timestamp: Date;
|
||||
};
|
||||
};
|
||||
|
||||
daysTraded: { [accountId: number]: number };
|
||||
dailyPnL: { [accountId: number]: { date: string; pnl: number }[] };
|
||||
fullDailyPnL: { [accountId: number]: { date: string; pnl: number }[] };
|
||||
lastFundDates: { [accountId: number]: string | null };
|
||||
fundTransactions: { [accountId: number]: { date: string; amount: number }[] };
|
||||
priorProfit: { [accountId: number]: number };
|
||||
autoLiqThresholds: { [accountId: number]: number };
|
||||
|
||||
fetchDaysComplete: boolean;
|
||||
syncComplete: boolean;
|
||||
lastFetchErrors: Record<string, string>;
|
||||
lastFetchRaw: Record<string, string>;
|
||||
recentEntityEvents: { entityType: string; eventType: string; entity: unknown; ts: number }[];
|
||||
products: { id: number; name: string }[];
|
||||
|
||||
fetchDaysTraded(onlyAccountIds?: number[]): Promise<{ failedAccounts: number }>;
|
||||
findFrontMonthContract(productName: string): Promise<PlatformContract | null>;
|
||||
fetchInstrumentFees(symbols: string[]): Promise<{ [symbol: string]: number }>;
|
||||
|
||||
sendOrder(
|
||||
accountId: number,
|
||||
contractSymbol: string,
|
||||
quantity: number,
|
||||
action: 'Buy' | 'Sell',
|
||||
orderType: 'Market' | 'Limit',
|
||||
price?: number
|
||||
): Promise<Record<string, unknown>>;
|
||||
|
||||
placeOrderNoWait(
|
||||
accountId: number,
|
||||
contractSymbol: string,
|
||||
quantity: number,
|
||||
action: 'Buy' | 'Sell',
|
||||
orderType: 'Market' | 'Limit',
|
||||
price?: number
|
||||
): Promise<{ orderId?: number }>;
|
||||
|
||||
placeOcoExit(
|
||||
accountId: number,
|
||||
contractSymbol: string,
|
||||
quantity: number,
|
||||
exitAction: 'Buy' | 'Sell',
|
||||
limitPrice: number,
|
||||
stopPrice: number,
|
||||
): Promise<{ orderId?: number }>;
|
||||
|
||||
disconnect(): void;
|
||||
onFill(orderId: number, callback: (fill: Record<string, unknown>) => void): void;
|
||||
}
|
||||
Reference in New Issue
Block a user