DXtrade sizing: volatility only (12h default hold); fees and every-day only for DXtrade

The symbol map's fixed notional per contract is gone: every DXtrade leg is
sized from the instrument's recent volatility for the firm's target hold
(blank = 12 h), and a candidate without a volatility isn't picked. Percent
commission and every-day trading are ignored on non-DXtrade firms, which keep
measured per-contract fees and the CME calendar.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-09-26 17:29:32 -05:00
co-authored by Claude Opus 5.5
parent 28f465508d
commit d01f03b293
9 changed files with 87 additions and 100 deletions
+5 -7
View File
@@ -31,7 +31,7 @@
*/
import axios from 'axios';
import { currentTradeDateCT, FIRM_RESET_UTC_HOUR } from './trading-logic';
import { currentTradeDateCT, FIRM_RESET_UTC_HOUR, DEFAULT_TARGET_HOLD_HOURS } from './trading-logic';
import {
saveDailyPnL, loadDailyPnL, loadAccountMeta, saveAccountMeta, loadFundTransactions, saveFundTransactions,
saveEndedCycleStart,
@@ -1102,8 +1102,8 @@ export class DXTradeClient implements PlatformClient {
/**
* The contract a CME root trades as on this firm right now: the cheapest
* tradable candidate from the symbol map, per unit of volatility when the
* firm sizes by target hold (see scoreCandidate). Sticky while an account
* tradable candidate from the symbol map, per unit of volatility (see
* scoreCandidate). Sticky while an account
* holds one of the candidates, cached briefly so a batch's lookups agree.
*/
public async findFrontMonthContract(root: string): Promise<PlatformContract | null> {
@@ -1134,13 +1134,13 @@ export class DXTradeClient implements PlatformClient {
const ref = this.referenceAccount();
if (!ref) return null;
const firm = getCachedFirm(this.cfg.firmId);
const targetHold = firm?.targetHoldHours ?? 0;
const targetHold = firm?.targetHoldHours || DEFAULT_TARGET_HOLD_HOURS;
const symbols = [...new Set(candidates.map((c) => c.symbol))];
const [insts, dets, quotes, vols] = await Promise.all([
this.instruments(symbols),
this.accountInstruments(ref.code, symbols),
this.quotes(ref.code, symbols),
targetHold > 0 ? this.volatility(ref.code, symbols) : Promise.resolve(new Map<string, { vol: number | null; candles: number }>()),
this.volatility(ref.code, symbols),
]);
const now = new Date();
@@ -1178,7 +1178,6 @@ export class DXTradeClient implements PlatformClient {
quoteAgeMs: quote && Number.isFinite(quote.time) ? Date.now() - quote.time : null,
inHours: inTradingHours(inst.tradingHours, now),
candles: vol?.candles ?? 0,
needVolatility: targetHold > 0,
minContractsOk: maxContracts === undefined || maxContracts >= minContracts,
currency: typeof inst.currency === 'string' ? inst.currency : undefined,
accountCurrency: ref.currency,
@@ -1204,7 +1203,6 @@ export class DXTradeClient implements PlatformClient {
pointValue: step * multiplier,
commissionPct: pct,
stepNotional,
fixedNotional: cand.notionalPerContract,
volatilityPerHour: vol?.vol ?? undefined,
spreadFraction: spread,
maxContracts,