fix(accounting): store net PnL (payout - net_cost) in close_pnl, migrate Paxton record from gross to net
CI/CD / build-and-push (push) Successful in 7s
CI/CD / build-and-push (push) Successful in 7s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c5ffc37820
commit
060fc89953
+1
-1
@@ -313,7 +313,7 @@ async def get_summary():
|
|||||||
# unrealized_pnl_est: open positions, edge_net × net_cost − fee.
|
# unrealized_pnl_est: open positions, edge_net × net_cost − fee.
|
||||||
# Estimated — uses model signal, not live price. Source: open trades.
|
# Estimated — uses model signal, not live price. Source: open trades.
|
||||||
# realized_pnl: closed positions with known resolution.
|
# realized_pnl: closed positions with known resolution.
|
||||||
# Exact — computed from (resolution − entry_price) × shares.
|
# Exact — payout − net_cost per trade (net of fee), matches logs/Telegram.
|
||||||
# total_pnl: sum of both.
|
# total_pnl: sum of both.
|
||||||
"unrealized_pnl_est": latest.get("unrealized_pnl_est") or 0,
|
"unrealized_pnl_est": latest.get("unrealized_pnl_est") or 0,
|
||||||
"realized_pnl": latest.get("realized_pnl") or 0,
|
"realized_pnl": latest.get("realized_pnl") or 0,
|
||||||
|
|||||||
+10
-3
@@ -173,7 +173,14 @@ class Database:
|
|||||||
|
|
||||||
resolution: 1.0 if YES resolved, 0.0 if NO resolved, None if unknown
|
resolution: 1.0 if YES resolved, 0.0 if NO resolved, None if unknown
|
||||||
(legacy closes, inversion fixes). When resolution is provided, close_pnl
|
(legacy closes, inversion fixes). When resolution is provided, close_pnl
|
||||||
is computed in SQL so it matches the stored entry_price and shares exactly.
|
is computed in SQL per row as payout − net_cost — NET of fee, the single
|
||||||
|
PnL definition shared with PaperExecutor.close_position() (logs/Telegram):
|
||||||
|
BUY_YES: resolution * shares − net_cost
|
||||||
|
BUY_NO: (1 − resolution) * shares − net_cost
|
||||||
|
paper.py aggregates payout − net_cost over these same open rows, so
|
||||||
|
SUM(close_pnl) per market equals the pnl it reports exactly. The
|
||||||
|
aggregate is intentionally NOT passed in as a parameter: writing it to
|
||||||
|
every row would double-count markets with more than one open trade.
|
||||||
"""
|
"""
|
||||||
async with self._pool.acquire() as conn:
|
async with self._pool.acquire() as conn:
|
||||||
# $3 is cast on every use: Postgres cannot infer the parameter type
|
# $3 is cast on every use: Postgres cannot infer the parameter type
|
||||||
@@ -186,9 +193,9 @@ class Database:
|
|||||||
resolution = $3::double precision,
|
resolution = $3::double precision,
|
||||||
close_pnl = CASE
|
close_pnl = CASE
|
||||||
WHEN $3::double precision IS NOT NULL AND direction = 'BUY_YES'
|
WHEN $3::double precision IS NOT NULL AND direction = 'BUY_YES'
|
||||||
THEN ($3::double precision - entry_price) * shares
|
THEN ($3::double precision * shares) - net_cost
|
||||||
WHEN $3::double precision IS NOT NULL AND direction = 'BUY_NO'
|
WHEN $3::double precision IS NOT NULL AND direction = 'BUY_NO'
|
||||||
THEN ((1.0 - $3::double precision) - entry_price) * shares
|
THEN ((1.0 - $3::double precision) * shares) - net_cost
|
||||||
ELSE NULL
|
ELSE NULL
|
||||||
END
|
END
|
||||||
WHERE market_id = $1 AND closed_at IS NULL
|
WHERE market_id = $1 AND closed_at IS NULL
|
||||||
|
|||||||
+4
-3
@@ -113,9 +113,10 @@ CREATE INDEX IF NOT EXISTS idx_trades_closed ON trades(closed_at) WHERE closed_a
|
|||||||
-- Fix 3: market resolution and realized P&L per trade
|
-- Fix 3: market resolution and realized P&L per trade
|
||||||
--
|
--
|
||||||
-- resolution: 1.0 if YES resolved, 0.0 if NO resolved, NULL if not yet settled.
|
-- resolution: 1.0 if YES resolved, 0.0 if NO resolved, NULL if not yet settled.
|
||||||
-- close_pnl: realized P&L in USDC at close time.
|
-- close_pnl: realized P&L in USDC at close time — NET of fee (payout − net_cost),
|
||||||
-- BUY_YES: (resolution - entry_price) * shares
|
-- the same definition PaperExecutor.close_position() reports in logs/Telegram.
|
||||||
-- BUY_NO: ((1 - resolution) - entry_price) * shares
|
-- BUY_YES: resolution * shares - net_cost
|
||||||
|
-- BUY_NO: (1 - resolution) * shares - net_cost
|
||||||
-- NULL if closed without a known resolution (legacy closes, inversion fixes).
|
-- NULL if closed without a known resolution (legacy closes, inversion fixes).
|
||||||
-- ─────────────────────────────────────────────────────────────────────────────
|
-- ─────────────────────────────────────────────────────────────────────────────
|
||||||
ALTER TABLE trades ADD COLUMN IF NOT EXISTS close_pnl DOUBLE PRECISION;
|
ALTER TABLE trades ADD COLUMN IF NOT EXISTS close_pnl DOUBLE PRECISION;
|
||||||
|
|||||||
Reference in New Issue
Block a user