Files
autofirmer-expanded/lib/trading-logic.ts
T
SenofyandClaude Sonnet 4.6 68075059d0 Fix min-day target for 0% consistency accounts + daysTraded consistency
trading-logic: when baseAmount=0 (consistency=0%), target cappedByFuture
directly instead of collapsing to minDayPnL. For a $4000 target with $150
min-day and 5 days, day 1 now correctly targets $3400 ($4000 - 4×$150)
then $150 for each remaining mandatory day.

tradovate-class: make fetchDaysTraded() public so auto-trade can call it
immediately after a trade exits. Fix daysTraded to count only positive-P&L
days from the FIFO results, consistent with computeDailyTarget's
positiveDays.length — previously counted all raw fill dates.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 17:33:55 -05:00

92 lines
3.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/** 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);
// When consistency = 0% (baseAmount = 0), there's no consistency-based upper bound —
// target cappedByFuture directly (make as much as possible today, reserve future days).
// When consistency > 0%, treat baseAmount as the consistency cap.
const consistencyCapped = baseAmount > 0 ? Math.min(baseAmount, cappedByFuture) : cappedByFuture;
const amount = Math.max(floor, consistencyCapped);
return { amount: Math.round(amount * 100) / 100, path };
}
return { amount: Math.round(baseAmount * 100) / 100, path };
}