/** Dollar-per-point value for common futures products. */ export const POINT_VALUES: { [symbol: string]: number } = { NQ: 20, MNQ: 2, ES: 50, MES: 5, YM: 5, MYM: 0.5, RTY: 50, M2K: 10, GC: 100, MGC: 10, SI: 50, CL: 1000, MCL: 100, NG: 10000, ZB: 1000, ZN: 1000, ZF: 1000, '6E': 125000, '6J': 12500000, '6B': 62500, }; /** * Compute the next trading day's profit target for an account. * * Path 1 – No positive trading days yet: * target = profitTarget × consistency * * Path 2 – At least one positive day exists: * maxDay = highest single-day P&L so far * realTarget = maxDay / consistency (the total profit at which maxDay ≤ consistency% of total) * needed = realTarget − totalProfit * * if needed > maxDay → target maxDay (still a long way from the real target; trade a normal day) * else → target needed (close to the real target; aim for exactly what's left) * * Min-day reservation (only when minDayPnL > 0): * When there are still mandatory trading days remaining, today's target is capped so that * enough profit is reserved for each future mandatory day to meet minDayPnL. * Cap = (profitTarget - totalProfit) − (remainingDaysAfterToday × minDayPnL) * Floor = minDayPnL (we must make at least this today) */ export function computeDailyTarget( profitTarget: number, consistency: number, totalProfit: number, dailyPnL: { date: string; pnl: number }[], minDayPnL: number = 0, // -999 or 0 = no minimum per day minTradingDays: number = 0 // 0 = no minimum trading days ): { amount: number; path: 'first_day' | 'normal_day' | 'reduced_day' } { const positiveDays = dailyPnL.filter((d) => d.pnl > 0); const daysTraded = positiveDays.length; // --- Base target via consistency logic --- let baseAmount: number; let path: 'first_day' | 'normal_day' | 'reduced_day'; if (daysTraded === 0) { baseAmount = profitTarget * consistency; path = 'first_day'; } else { const maxDay = Math.max(...positiveDays.map((d) => d.pnl)); const realTarget = maxDay / consistency; const needed = realTarget - totalProfit; if (needed > maxDay) { baseAmount = maxDay; path = 'normal_day'; } else { baseAmount = Math.max(0, needed); path = 'reduced_day'; } } // --- Min-day reservation (only when minDayPnL is a positive value) --- const effectiveMinDay = minDayPnL > 0 ? minDayPnL : 0; if (effectiveMinDay > 0 && minTradingDays > daysTraded) { const remaining = profitTarget - totalProfit; // intentionally NOT clamped — can be negative if (remaining <= 0) { // Profit target already met but mandatory trading days not yet satisfied. // Trade exactly minDayPnL each remaining day. return { amount: effectiveMinDay, path }; } const remainingMandatoryDays = minTradingDays - daysTraded; // includes today const futureReserve = (remainingMandatoryDays - 1) * effectiveMinDay; // Cap: don't take more than what's available after reserving future days const cappedByFuture = remaining - futureReserve; // Floor: must make at least minDayPnL today (or whatever is left if less) const floor = Math.min(effectiveMinDay, remaining); const amount = Math.max(floor, Math.min(baseAmount, cappedByFuture)); return { amount: Math.round(amount * 100) / 100, path }; } return { amount: Math.round(baseAmount * 100) / 100, path }; }