- Add SymbolSettings interface with enabled/positionSize/leverage fields - Implement per-symbol ENV variables (SOLANA_*, ETHEREUM_*) - Add SOL and ETH sections to settings UI with enable/disable toggles - Add symbol-specific test buttons (SOL LONG/SHORT, ETH LONG/SHORT) - Update execute and test endpoints to check symbol enabled status - Add real-time risk/reward calculator per symbol - Rename 'Position Sizing' to 'Global Fallback' for clarity - Fix position manager P&L calculation for externally closed positions - Fix zero P&L bug affecting 12 historical trades - Add SQL scripts for recalculating historical P&L data - Move archive TypeScript files to .archive to fix build Defaults: - SOL: 10 base × 10x leverage = 100 notional (profit trading) - ETH: base × 1x leverage = notional (data collection) - Global: 10 × 10x for BTC and other symbols Configuration priority: Per-symbol ENV > Market config > Global ENV > Defaults
80 lines
2.6 KiB
SQL
80 lines
2.6 KiB
SQL
-- Fix Zero P&L Trades
|
|
-- This script recalculates P&L for trades that were incorrectly recorded as $0.00
|
|
-- Created: 2025-11-03
|
|
-- Backup: backup_before_pnl_fix_20251103_091248.sql
|
|
|
|
-- First, let's see what we're fixing
|
|
SELECT
|
|
id,
|
|
symbol,
|
|
direction,
|
|
ROUND("entryPrice"::numeric, 2) as entry,
|
|
ROUND("exitPrice"::numeric, 2) as exit,
|
|
"positionSizeUSD",
|
|
leverage,
|
|
"realizedPnL" as current_pnl,
|
|
"exitReason"
|
|
FROM "Trade"
|
|
WHERE "realizedPnL" = 0
|
|
AND "exitReason" IS NOT NULL
|
|
AND "exitPrice" IS NOT NULL
|
|
AND "exitOrderTx" IN ('ON_CHAIN_ORDER', 'UNKNOWN_CLOSURE')
|
|
ORDER BY "entryTime" DESC;
|
|
|
|
-- Calculate and update P&L for zero-P&L trades
|
|
-- Formula: realizedPnL = (positionSizeUSD * profitPercent * leverage) / 100
|
|
-- profitPercent = ((exitPrice - entryPrice) / entryPrice) * 100 * (direction multiplier)
|
|
|
|
UPDATE "Trade"
|
|
SET
|
|
"realizedPnL" = CASE
|
|
WHEN direction = 'long' THEN
|
|
-- Long: profit when exit > entry
|
|
("positionSizeUSD" * ((("exitPrice" - "entryPrice") / "entryPrice") * 100) * leverage) / 100
|
|
WHEN direction = 'short' THEN
|
|
-- Short: profit when exit < entry
|
|
("positionSizeUSD" * ((("entryPrice" - "exitPrice") / "entryPrice") * 100) * leverage) / 100
|
|
ELSE 0
|
|
END,
|
|
"realizedPnLPercent" = CASE
|
|
WHEN direction = 'long' THEN
|
|
((("exitPrice" - "entryPrice") / "entryPrice") * 100) * leverage
|
|
WHEN direction = 'short' THEN
|
|
((("entryPrice" - "exitPrice") / "entryPrice") * 100) * leverage
|
|
ELSE 0
|
|
END,
|
|
"updatedAt" = NOW()
|
|
WHERE "realizedPnL" = 0
|
|
AND "exitReason" IS NOT NULL
|
|
AND "exitPrice" IS NOT NULL
|
|
AND "exitOrderTx" IN ('ON_CHAIN_ORDER', 'UNKNOWN_CLOSURE');
|
|
|
|
-- Show the results after fix
|
|
SELECT
|
|
id,
|
|
symbol,
|
|
direction,
|
|
ROUND("entryPrice"::numeric, 2) as entry,
|
|
ROUND("exitPrice"::numeric, 2) as exit,
|
|
ROUND("positionSizeUSD"::numeric, 2) as size,
|
|
leverage,
|
|
ROUND("realizedPnL"::numeric, 2) as fixed_pnl,
|
|
ROUND("realizedPnLPercent"::numeric, 2) as pnl_percent,
|
|
"exitReason"
|
|
FROM "Trade"
|
|
WHERE "exitOrderTx" IN ('ON_CHAIN_ORDER', 'UNKNOWN_CLOSURE')
|
|
AND "exitReason" IS NOT NULL
|
|
ORDER BY "entryTime" DESC;
|
|
|
|
-- Show new total P&L
|
|
SELECT
|
|
COUNT(*) as total_trades,
|
|
SUM(CASE WHEN "realizedPnL" > 0 THEN 1 ELSE 0 END) as wins,
|
|
SUM(CASE WHEN "realizedPnL" <= 0 THEN 1 ELSE 0 END) as losses,
|
|
ROUND(SUM("realizedPnL")::numeric, 2) as total_pnl,
|
|
ROUND(AVG(CASE WHEN "realizedPnL" > 0 THEN "realizedPnL" END)::numeric, 2) as avg_win,
|
|
ROUND(AVG(CASE WHEN "realizedPnL" <= 0 THEN "realizedPnL" END)::numeric, 2) as avg_loss
|
|
FROM "Trade"
|
|
WHERE "entryTime" >= NOW() - INTERVAL '7 days'
|
|
AND "exitReason" IS NOT NULL;
|