diff --git a/app/accounts/[id]/page.tsx b/app/accounts/[id]/page.tsx index 07adcfd..fc85491 100644 --- a/app/accounts/[id]/page.tsx +++ b/app/accounts/[id]/page.tsx @@ -247,7 +247,7 @@ export default function AccountPage() { ? Math.round((account.amount - cfg.accountSize) * 100) / 100 : Math.round(fifoTotal * 100) / 100; const profitPct = cfg?.accountSize ? (totalProfit / cfg.accountSize) * 100 : null; - const profitPassed = cfg != null && totalProfit >= cfg.profitTarget; + const profitPassed = cfg != null && totalProfit >= (account.effectiveProfitTarget ?? cfg.profitTarget); // dailyTarget is computed server-side in the state API — single source of truth. const dailyTarget = account.dailyTarget ?? null; const lossPassed = !hasLossLimit || (cfg != null && totalProfit >= cfg.minDayPnL); @@ -379,7 +379,7 @@ export default function AccountPage() { { try { return JSON.parse(cfg.withdrawal_stages ?? '[]'); } catch { return []; } })(); const effective = resolveEffectiveConfig( @@ -52,6 +53,15 @@ export async function GET() { const equityProfit = cash.amount - cfg.account_size; const target = computeDailyTarget(effective.profitTarget, effective.consistency, dailyPnL, cfg.min_day_pnl, effective.minTradingDays, equityProfit); dailyTarget = target; + + // 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. + const qualifying = cfg.min_day_pnl === 0 ? dailyPnL : dailyPnL.filter((d) => d.pnl >= cfg.min_day_pnl); + const maxDay = qualifying.length > 0 ? Math.max(...qualifying.map((d) => d.pnl)) : 0; + const consistencyReal = (effective.consistency > 0 && effective.consistency < 1 && maxDay > 0) + ? maxDay / effective.consistency : 0; + effectiveProfitTarget = Math.max(effective.profitTarget, consistencyReal); // Condition 1: profit target already exceeded (target=0), still need days → any activity counts // Condition 2: target > 0 → must have made at least the computed daily target if (target) { @@ -75,6 +85,7 @@ export async function GET() { totalProfit, targetHit, dailyTarget, + effectiveProfitTarget, dailyPnL, fullDailyPnL: client.fullDailyPnL?.[acc.id] ?? loadDailyPnL(acc.id), fundTransactions: displayFundTxns, diff --git a/app/page.tsx b/app/page.tsx index d0d1fd5..5728a76 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -135,7 +135,7 @@ function AccountRow({ account, firm, hideDead, privacy }: { account: AccountStat
- ${cfg?.profitTarget?.toLocaleString() ?? '—'} + ${(account.effectiveProfitTarget ?? cfg?.profitTarget ?? 0).toLocaleString(undefined, { maximumFractionDigits: 2 })} {account.dailyTarget && ( ${fmt(account.dailyTarget.amount)} today )} diff --git a/types.ts b/types.ts index a44c5bd..ec98a82 100644 --- a/types.ts +++ b/types.ts @@ -36,6 +36,8 @@ export interface AccountState { targetHit: 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; + /** 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. */