Show the next trade's stop next to the daily target

Stop-enabled accounts show an amber "stop $X" beside the day target:
the day-1 net floor (live against realized P&L) or 2x a min-day's
target, mirroring exactly what the trade path will place — and nothing
when the next trade rides stopless.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-09-11 20:24:44 -05:00
co-authored by Claude Fable 5
parent 6685a75864
commit 1bca441247
3 changed files with 37 additions and 2 deletions
+27 -1
View File
@@ -3,7 +3,10 @@ import { loadDailyPnL } from '@/lib/db';
import { getClients } from '@/lib/clients';
import { getCachedCatalog } from '@/lib/firm-catalog';
import { getAccountConfig, getInferredSize, matchAccountType } from '@/lib/account-type-resolver';
import { combineCmeSessions, computeDayPlan, resolveEffectiveConfig, currentTradeDateCT, LEG_COMPLETION_EPSILON } from '@/lib/trading-logic';
import {
combineCmeSessions, computeDayPlan, resolveEffectiveConfig, currentTradeDateCT,
BIG_DAY_THRESHOLD, FIRST_DAY_STOP, LEG_COMPLETION_EPSILON, MIN_DAY_STOP_MULT,
} from '@/lib/trading-logic';
export async function GET() {
try {
@@ -66,6 +69,7 @@ export async function GET() {
let dailyTarget: { amount: number; path: 'first_day' | 'normal_day' | 'reduced_day' } | null = null;
let remainingToday: number | null = null;
let effectiveProfitTarget: number | null = null;
let nextStop: number | null = null;
if (cfg && !isDead) {
const effective = resolveEffectiveConfig(
cfg.profitTarget,
@@ -85,6 +89,27 @@ export async function GET() {
dailyTarget = plan ? { amount: plan.dayTarget, path: plan.path } : null;
remainingToday = plan?.remainingToday ?? null;
// The stop the next trade would carry under the obfuscation
// options, mirroring obfuscationStopDollars in auto-trade:
// day 1 keeps the day's net floor at −$1,000, min days stop
// at 2× the target, and the day after a loss rides stopless.
if (plan && (cfg.firstDayStop || cfg.minDayStop)) {
const prior = dailyPnL
.filter((d) => d.date < combined.tradeDate && d.pnl !== 0)
.sort((a, b) => a.date.localeCompare(b.date));
const recoveryDay = prior.length > 0 && prior[prior.length - 1].pnl < 0;
if (!recoveryDay) {
let stop = Infinity;
if (cfg.firstDayStop && prior.length === 0) {
stop = Math.max(0, Math.round((FIRST_DAY_STOP + combined.realizedPnL) * 100) / 100);
}
if (cfg.minDayStop && plan.dayTarget <= BIG_DAY_THRESHOLD) {
stop = Math.min(stop, MIN_DAY_STOP_MULT * plan.dayTarget);
}
if (Number.isFinite(stop) && stop > 0) nextStop = Math.round(stop * 100) / 100;
}
}
// Effective profit target = max(stage target, consistency realTarget).
// If a big day forces the consistency rule, the account must reach maxDay/consistency
// in total trading profit for the stage, not just profitTarget.
@@ -168,6 +193,7 @@ export async function GET() {
targetHit,
stage,
dailyTarget,
nextStop,
remainingToday,
effectiveProfitTarget,
dailyPnL,
+6 -1
View File
@@ -350,7 +350,12 @@ function AccountRow({ account, firm, hideDead, privacy, onAssigned }: {
</span>
</div>
{account.dailyTarget && (
<span className="text-xs text-slate-400">${fmt(account.dailyTarget.amount)} today</span>
<span className="text-xs text-slate-400">
${fmt(account.dailyTarget.amount)} today
{account.nextStop !== null && (
<span className="text-amber-600" title="The next trade's stop — dollars it may lose before booking the day"> · stop ${fmt(account.nextStop)}</span>
)}
</span>
)}
</div>
</td>