DXtrade: count closed-trade P&L, week-long volatility, broker leverage caps, swap in the take-profit

- 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>
This commit is contained in:
Brandon Li
2026-09-26 18:11:42 -05:00
co-authored by Claude Opus 5.5
parent 675b4c89f8
commit a2d9df5ba4
10 changed files with 309 additions and 81 deletions
+12 -3
View File
@@ -7,7 +7,7 @@ import { historyFresh, type PlatformContract } from '@/lib/platform-client';
import type { AccountState } from '@/types';
import {
combineCmeSessions, computeDayPlan, cycleCompletion, resolveEffectiveConfig, currentTradeDateCT,
obfuscationStopDollars, dllRoom as computeDllRoom, dllStopDollars, botStopsActive, sizeNotional,
obfuscationStopDollars, dllRoom as computeDllRoom, dllStopDollars, botStopsActive, sizeNotional, notionalCap,
DEFAULT_TARGET_HOLD_HOURS,
LEG_COMPLETION_EPSILON,
} from '@/lib/trading-logic';
@@ -126,7 +126,8 @@ export async function GET() {
// DXtrade: size the next leg the way fireLeg would, on the
// instrument the selector last picked and today's measured
// volatility, to show how long it is expected to hold.
// volatility — under the same notional and margin caps —
// to show how long it is expected to hold.
const pick = (client as { lastPickedContract?: PlatformContract | null }).lastPickedContract;
if (plan && plan.remainingToday > 0 && pick?.stepNotional && pick.volatilityPerHour) {
const pct = pick.commissionPct ?? f.commissionPct ?? 0;
@@ -145,7 +146,13 @@ export async function GET() {
commissionPct: pct,
spreadFraction: pick.spreadFraction,
financingPctPerDay: f.financingPctPerDay ?? 0,
maxNotional: cfg.maxNotional ?? 0,
// The next leg opens flat: while this one is open its
// margin is tied up, so size against the balance.
maxNotional: notionalCap({
maxNotional: cfg.maxNotional ?? 0,
marginRate: pick.marginRate,
availableFunds: client.positions[acc.id] ? cash.amount : (cash.availableFunds ?? cash.amount),
}),
});
if (sizing) {
holdEstimate = {
@@ -154,6 +161,8 @@ export async function GET() {
notional: Math.round(sizing.notional),
volatilityPerDay: pick.volatilityPerHour * Math.sqrt(24),
winProbability: sizing.winProbability,
swapReserve: sizing.swapReserve,
leverage: pick.marginRate ? Math.round(10 / pick.marginRate) / 10 : null,
};
}
}
+5 -2
View File
@@ -393,8 +393,11 @@ function AccountRow({ account, firm, hideDead, privacy, onAssigned }: {
{account.holdEstimate && (
<span
className="text-slate-500"
title={`Next leg on ${account.holdEstimate.symbol}: $${Math.round(account.holdEstimate.notional).toLocaleString()} notional at today's measured volatility of ${(account.holdEstimate.volatilityPerDay * 100).toFixed(2)}%/day`
+ (account.holdEstimate.winProbability !== null ? `, wins ~${Math.round(account.holdEstimate.winProbability * 100)}% of the time` : '')}
title={`Next leg on ${account.holdEstimate.symbol}: $${Math.round(account.holdEstimate.notional).toLocaleString()} notional`
+ (account.holdEstimate.leverage !== null ? ` (${account.holdEstimate.leverage}:1 max)` : '')
+ ` at a measured volatility of ${(account.holdEstimate.volatilityPerDay * 100).toFixed(2)}%/day over the past week`
+ (account.holdEstimate.winProbability !== null ? `, wins ~${Math.round(account.holdEstimate.winProbability * 100)}% of the time` : '')
+ (account.holdEstimate.swapReserve > 0 ? `; its take-profit carries ~$${fmt(account.holdEstimate.swapReserve)} of expected swap` : '')}
>
{' · hold ~'}{account.holdEstimate.hours < 48 ? `${Math.round(account.holdEstimate.hours)}h` : `${(account.holdEstimate.hours / 24).toFixed(1)}d`}
</span>