Files
Brandon LiandClaude Opus 4.6 70b1362d3e Add per-stage withdrawal targets with consistency and min trading days
- Add withdrawal stage system: each stage defines profit target, consistency,
  and min trading days for post-withdrawal challenge cycles
- Target Same Equity mode accounts for withdrawn amounts when computing
  effective profit target (profitTarget - remainingProfit)
- Store fund transaction timestamps for time-aware cycle filtering
  (withdrawals before 9 AM CT include that day in new cycle)
- Expose full P&L history (fullDailyPnL) for calendar/equity curve display
  across all cycles, with DB fallback for pre-restart data
- Show stage number (#1, #2, etc.) on calendar cells
- Hide consistency reference line when consistency is 0% or 100%
- Settings UI: "After First W/D" column with same-equity checkbox,
  expandable stage sub-rows with profit/consistency/days inputs
- Default target_same_equity to 1 for new and existing account configs

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 05:27:13 -05:00

88 lines
2.8 KiB
TypeScript

import { NextRequest, NextResponse } from 'next/server';
import { updateAccountConfig, deleteAccountConfig } from '@/lib/db';
export async function PUT(
req: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id: idStr } = await params;
const id = parseInt(idStr, 10);
if (isNaN(id)) {
return NextResponse.json({ error: 'Invalid id' }, { status: 400 });
}
const body = await req.json() as {
prefix?: string;
profitTarget?: number;
consistency?: number;
minDayPnL?: number;
minTradingDays?: number;
accountSize?: number;
maxLoss?: number;
maxPositionSize?: number;
targetSameEquity?: boolean;
withdrawalStages?: { profit: number; consistency: number; minTradingDays: number }[];
};
const { prefix, profitTarget, consistency, minDayPnL, minTradingDays, accountSize, maxLoss, maxPositionSize, targetSameEquity, withdrawalStages } = body;
if (
typeof prefix !== 'string' || !prefix.trim() ||
typeof profitTarget !== 'number' ||
typeof consistency !== 'number' ||
typeof minDayPnL !== 'number' ||
typeof minTradingDays !== 'number' ||
typeof accountSize !== 'number'
) {
return NextResponse.json({ error: 'Invalid body' }, { status: 400 });
}
try {
const updated = updateAccountConfig(id, {
prefix: prefix.trim(),
profitTarget,
consistency,
minDayPnL,
minTradingDays,
accountSize,
maxLoss: maxLoss ?? 0,
maxPositionSize: maxPositionSize ?? 0,
targetSameEquity: targetSameEquity ?? false,
withdrawalStages: withdrawalStages ?? [],
});
if (!updated) {
return NextResponse.json({ error: 'Account config not found' }, { status: 404 });
}
return NextResponse.json({ success: true });
} catch (err) {
console.error('[PUT /api/account-configs/:id]', err);
return NextResponse.json({ error: 'Failed to update' }, { status: 500 });
}
}
export async function DELETE(
_req: NextRequest,
{ params }: { params: Promise<{ id: string }> }
) {
const { id: idStr } = await params;
const id = parseInt(idStr, 10);
if (isNaN(id)) {
return NextResponse.json({ error: 'Invalid id' }, { status: 400 });
}
try {
const deleted = deleteAccountConfig(id);
if (!deleted) {
return NextResponse.json({ error: 'Account config not found' }, { status: 404 });
}
return NextResponse.json({ success: true });
} catch (err) {
console.error('[DELETE /api/account-configs/:id]', err);
return NextResponse.json({ error: 'Failed to delete' }, { status: 500 });
}
}