Drain days draw from a $4–$15 half-dollar grid

23 deterministic values per (account, date) instead of $5/$10/$15; the
qualifying floor moves to the grid minimum so every draw counts toward
the cycle. The per-stage min-day field no longer drives the amount.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Brandon Li
2026-09-13 13:57:06 -05:00
co-authored by Claude Fable 5
parent fc65b4340d
commit 5e14daa669
+14 -5
View File
@@ -6,7 +6,8 @@ export interface WithdrawalStage {
* days of ~minDayPnL (tiny MNQ trades), then wait for the withdrawal. */
drain?: boolean;
/** Drain stages only: the per-day booked amount (default $5; randomized
* $5–$15 by drainDayAmount). */
* the fixed $4–$15 half-dollar grid by drainDayAmount; this field is
* kept for the wire format but no longer drives the amount). */
minDayPnL?: number;
/** Payout overrides for the withdrawal that completes THIS stage; absent
* fields fall back to the account type's defaults. */
@@ -62,7 +63,9 @@ export function resolveEffectiveConfig(
profitTarget: 0,
consistency: 0,
minTradingDays: stage.minTradingDays || minTradingDays,
minDayPnL: stage.minDayPnL || 5,
// Drain amounts come from the fixed $4–$15 grid, so the
// qualifying bar sits at the grid floor — every draw counts.
minDayPnL: DRAIN_DAY_MIN,
drain: true,
};
}
@@ -138,14 +141,20 @@ export function currentTradeDateCT(now: Date = new Date()): string {
* depending on the (account, trade date) pair). Seeded like dailyBump so
* every consumer of the plan computes the same number.
*/
export function drainDayAmount(accountId: number, tradeDate: string, minDay: number): number {
/** Drain-day target grid: $4–$15 in $0.50 steps (23 values), always traded
* on MNQ. Drain days qualify at ≥ DRAIN_DAY_MIN, so every draw counts. */
export const DRAIN_DAY_MIN = 4;
export const DRAIN_DAY_MAX = 15;
const DRAIN_DAY_STEPS = Math.round((DRAIN_DAY_MAX - DRAIN_DAY_MIN) / 0.5) + 1;
export function drainDayAmount(accountId: number, tradeDate: string): number {
const key = `${accountId}|drain|${tradeDate}`;
let hash = 0x811c9dc5;
for (let i = 0; i < key.length; i++) {
hash ^= key.charCodeAt(i);
hash = Math.imul(hash, 0x01000193) >>> 0;
}
return round2(minDay + (hash % 21) * 0.5);
return round2(DRAIN_DAY_MIN + (hash % DRAIN_DAY_STEPS) * 0.5);
}
/**
@@ -759,7 +768,7 @@ export function computeDayPlan(
: priorDays.filter((d) => d.pnl !== 0);
const dayTarget = qualifying.length >= minTradingDays
? 0
: drainDayAmount(accountId, tradeDate, minDayPnL || 5);
: drainDayAmount(accountId, tradeDate);
return {
dayTarget,
remainingToday: round2(dayTarget - realizedPnL),