Skip to content

Commit 56df5f7

Browse files
committed
fix(pnl): skip invalid PnL; broadcast close only with real PnL
- Handle undefined/null/NaN in formatPnL by returning an empty string - Show PnL in toasts only when a valid formatted value exists - Default toast variant to success when PnL is missing/zero - Stop broadcasting position_closed on immediate close; only send position_update and rely on ORDER_TRADE_UPDATE to broadcast position_closed with actual PnL This prevents misleading "PnL: $NaN"/zero displays and avoids premature or duplicate close notifications, improving accuracy and UX.
1 parent 6cdb83f commit 56df5f7

File tree

2 files changed

+12
-14
lines changed

2 files changed

+12
-14
lines changed

src/hooks/useOrderNotifications.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ export function useOrderNotifications(customWsUrl?: string) {
2727
}).format(qty);
2828
};
2929

30-
const formatPnL = (pnl: number) => {
30+
const formatPnL = (pnl: number | undefined) => {
31+
if (pnl === undefined || pnl === null || isNaN(pnl)) {
32+
return '';
33+
}
3134
const formatted = new Intl.NumberFormat('en-US', {
3235
style: 'currency',
3336
currency: 'USD',
@@ -76,7 +79,8 @@ export function useOrderNotifications(customWsUrl?: string) {
7679
case 'order_filled': {
7780
const { symbol, side, executedQty, price, orderType, pnl } = message.data;
7881
const priceStr = price ? ` at $${formatPrice(price)}` : '';
79-
const pnlStr = pnl !== undefined && pnl !== 0 ? ` • PnL: ${formatPnL(pnl)}` : '';
82+
const formattedPnl = formatPnL(pnl);
83+
const pnlStr = formattedPnl ? ` • PnL: ${formattedPnl}` : '';
8084

8185
if (orderType === 'STOP_MARKET' || orderType === 'STOP') {
8286
toast.warning(
@@ -133,8 +137,9 @@ export function useOrderNotifications(customWsUrl?: string) {
133137

134138
case 'position_closed': {
135139
const { symbol, side, quantity, pnl } = message.data;
136-
const pnlStr = pnl !== undefined ? ` • PnL: ${formatPnL(pnl)}` : '';
137-
const variant = pnl >= 0 ? 'success' : 'warning';
140+
const formattedPnl = formatPnL(pnl);
141+
const pnlStr = formattedPnl ? ` • PnL: ${formattedPnl}` : '';
142+
const variant = pnl && pnl >= 0 ? 'success' : pnl && pnl < 0 ? 'warning' : 'success';
138143

139144
toast[variant](
140145
`💰 Position closed: ${symbol}`,

src/lib/bot/positionManager.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -664,17 +664,10 @@ export class PositionManager extends EventEmitter implements PositionTracker {
664664
const previousAmt = parseFloat(previousPosition.positionAmt);
665665
console.log(`PositionManager: Position ${previousKey} fully closed`);
666666

667-
// Broadcast position closed event
667+
// Don't broadcast position_closed here - it will be broadcast with actual PnL in ORDER_TRADE_UPDATE
668+
// Only broadcast position_update for UI state updates
668669
if (this.statusBroadcaster) {
669-
this.statusBroadcaster.broadcastPositionClosed({
670-
symbol: symbol,
671-
side: previousAmt > 0 ? 'LONG' : 'SHORT',
672-
quantity: Math.abs(previousAmt),
673-
pnl: 0, // Will be updated by ORDER_TRADE_UPDATE
674-
reason: 'Position Closed',
675-
});
676-
677-
// Also broadcast position_update with type closed for compatibility
670+
// Broadcast position_update with type closed for compatibility
678671
this.statusBroadcaster.broadcastPositionUpdate({
679672
symbol: symbol,
680673
side: previousAmt > 0 ? 'LONG' : 'SHORT',

0 commit comments

Comments
 (0)