Overview
Your portfolio is your trading command center. It displays all your active positions, historical trades, and calculates your real-time profit and loss across all events.
Portfolio values update automatically as market prices change, giving you instant feedback on your trading performance.
Accessing your portfolio
Navigate to /portfolio or click “Portfolio” in the main navigation to view your trading dashboard.
Portfolio structure
The portfolio is divided into key sections:
Current returns Aggregate P&L across all active positions
Active trades Open positions in ongoing events
Past trades Settled positions with realized gains/losses
Current returns
At the top of your portfolio, see your total unrealized profit or loss:
interface PortfolioProps {
currentReturns : number ;
trades : Trade [];
onExit : ( id : string ) => void ;
}
< div className = "text-center mb-6" >
< p className = "text-lg font-semibold" > Current Returns </ p >
< p className = { `text-3xl font-bold ${
currentReturns >= 0 ? "text-green-500" : "text-red-500"
} ` } >
{ currentReturns >= 0 ? "+" : "-" }₹{ Math . abs ( currentReturns ). toFixed ( 2 )}
{ currentReturns >= 0 ? (
< ArrowUpIcon className = "inline ml-2 h-6 w-6" />
) : (
< ArrowDownIcon className = "inline ml-2 h-6 w-6" />
)}
</ p >
</ div >
Calculating returns
Current returns = Sum of (Current market value - Cost basis) for all active trades
Example:
Trade 1: Bought 10 YES at ₹7.00 = ₹70 cost, now worth ₹80 (+₹10)
Trade 2: Bought 5 NO at ₹3.00 = ₹15 cost, now worth ₹10 (-₹5)
Total returns : +₹5
Returns are unrealized until you exit the position or the event settles. Market prices can change before settlement.
Active trades
This section displays all your open positions in ongoing events.
Trade data structure
interface Trade {
id : string ; // Unique trade identifier
title : string ; // Event title
price : number ; // Your entry price
quantity : number ; // Number of units
type : "YES" | "NO" ; // Position type
gainloss : number | null ; // Current unrealized P&L
status : "ACTIVE" | "PAST" ; // Trade status
}
Active trade card
Each active position shows:
< Card className = "bg-gray-800 border-gray-700" >
< CardContent className = "p-4" >
< div className = "flex justify-between items-center" >
< div >
< h3 className = "font-semibold text-lg mb-2" >
{ trade . title }
</ h3 >
< p className = "text-sm text-gray-400" >
Price : ₹{ trade . price . toFixed ( 2 )} | Quantity : { trade . quantity }
</ p >
</ div >
< div className = "flex items-center space-x-4" >
< span className = { `text-sm font-medium px-2 py-1 rounded ${
trade . type === "YES"
? "bg-blue-500 text-white"
: "bg-red-500 text-white"
} ` } >
{ trade . type . toUpperCase ()}
</ span >
< Button
onClick = {() => onExit (trade.id)}
variant = "destructive"
size = "sm"
className = "bg-red-600 hover:bg-gray-600"
>
Exit
</ Button >
</ div >
</ div >
</ CardContent >
</ Card >
The average price you paid per unit:
For single orders: Your order price
For multiple fills: Weighted average
Example:
Bought 5 units at ₹7.00 = ₹35
Bought 5 units at ₹7.50 = ₹37.50
Average entry: (₹35 + ₹37.50) / 10 = ₹7.25
Total units in your position:
Sum of all matched orders for this event and side
Each unit pays ₹10 if you win
Example:
10 YES units × ₹10 = ₹100 potential payout
YES (Blue) : You profit if event occurs
NO (Red) : You profit if event doesn’t occur
You can hold both YES and NO positions on the same event (hedging).
Unrealized profit or loss based on current market price: For YES positions: P&L = (Current YES price - Entry price) × Quantity
For NO positions: P&L = (Current NO price - Entry price) × Quantity
Updates in real-time via WebSocket.
Exiting positions
You can close positions before event settlement.
Exit flow
Click Exit button
In your active trades section, click “Exit” on the position you want to close.
System places counter-order
The system automatically places an opposing order:
If you hold YES: Places NO order
If you hold NO: Places YES order
At current market price
For your full quantity
Order matches
Your exit order is matched against existing orders in the order book.
Position closed
Once fully matched:
Your position is closed
P&L is realized
Funds return to available balance
Trade moves to “Past Trades”
Exit implementation
const handleExit = async ( tradeId : string ) => {
const trade = activeTrades . find ( t => t . id === tradeId );
if ( ! trade ) return ;
// Determine opposing side
const exitSide = trade . type === "YES" ? "no" : "yes" ;
// Get current market price
const currentPrice = await getCurrentMarketPrice (
trade . eventId ,
exitSide
);
// Place exit order
const response = await fetch ( '/api/placeorder' , {
method: 'POST' ,
headers: { 'Content-Type' : 'application/json' },
body: JSON . stringify ({
market: trade . eventId ,
price: currentPrice ,
quantity: trade . quantity ,
side: exitSide ,
userId: session . user . id
})
});
// Update UI
if ( response . ok ) {
// Move to past trades
setPastTrades ([ ... pastTrades , {
... trade ,
status: "PAST" ,
gainloss: calculateRealizedPL ( trade , currentPrice )
}]);
// Remove from active
setActiveTrades ( activeTrades . filter ( t => t . id !== tradeId ));
}
};
Exit orders execute at market price, which may differ from the price shown when you clicked Exit if the market moved.
Past trades
This section shows your trading history with realized gains and losses.
Past trade card
< Card className = "bg-gray-800 border-gray-700" >
< CardContent className = "p-4" >
< div className = "flex justify-between items-center" >
< div >
< h3 className = "font-semibold text-lg mb-2" >
{ trade . title }
</ h3 >
< p className = "text-sm text-gray-400" >
Price : ₹{ trade . price . toFixed ( 2 )} | Quantity : { trade . quantity }
</ p >
< p className = { `text-sm font-semibold ${
trade . gainloss !== null && trade . gainloss >= 0
? "text-green-500"
: "text-red-500"
} ` } >
Gain / Loss :
{ trade . gainloss !== null
? trade . gainloss >= 0 ? "+" : "-"
: "" }
₹{ Math . abs ( trade . gainloss || 0 ). toFixed ( 2 )}
</ p >
</ div >
< div className = "flex items-center space-x-4" >
< span className = { `text-sm font-medium px-2 py-1 rounded ${
trade . type === "YES"
? "bg-blue-500 text-white"
: "bg-red-500 text-white"
} ` } >
{ trade . type . toUpperCase ()}
</ span >
</ div >
</ div >
</ CardContent >
</ Card >
Gain/Loss calculation
For settled events:
If you won:
const payout = quantity * 10 ; // ₹10 per unit
const cost = quantity * entryPrice ;
const gainLoss = payout - cost ;
Example (YES winner):
Bought 10 YES at ₹7.00 = ₹70 cost
Event outcome: YES
Payout: 10 × ₹10 = ₹100
Gain : ₹100 - ₹70 = +₹30
If you lost:
const payout = 0 ; // Position expires worthless
const cost = quantity * entryPrice ;
const gainLoss = payout - cost ;
Example (NO loser):
Bought 5 NO at ₹3.00 = ₹15 cost
Event outcome: YES (you had NO)
Payout: ₹0
Loss : ₹0 - ₹15 = -₹15
For manually exited positions:
const entryValue = entryQuantity * entryPrice ;
const exitValue = exitQuantity * exitPrice ;
const gainLoss = exitValue - entryValue ;
Filtering trades
The portfolio component filters trades by status:
const activeTrades = trades . filter ( trade => trade . status === "ACTIVE" );
const pastTrades = trades . filter ( trade => trade . status === "PAST" );
return (
< div >
< div className = "mb-8" >
< h3 className = "text-xl font-semibold mb-4" > Active Trades </ h3 >
{ activeTrades . length > 0 ? (
< div className = "space-y-4" >
{ activeTrades . map ( trade => (
< TradeCard key = {trade. id } trade = { trade } />
))}
</ div >
) : (
< p className = "text-gray-400 text-center" > No active trades . </ p >
)}
</ div >
< div >
< h3 className = "text-xl font-semibold mb-4" > Past Trades </ h3 >
{ pastTrades . length > 0 ? (
< div className = "space-y-4" >
{ pastTrades . map ( trade => (
< TradeCard key = {trade. id } trade = { trade } />
))}
</ div >
) : (
< p className = "text-gray-400 text-center" > No past trades . </ p >
)}
</ div >
</ div >
);
Fetching trade data
Trades are fetched from the database using Prisma:
export async function getTrades ( userId : string ) {
try {
const trades = await prisma . trade . findMany ({
where: { userId },
include: {
event: {
select: {
title: true ,
status: true
}
}
},
orderBy: { createdAt: 'desc' }
});
return trades . map ( trade => ({
id: trade . id ,
title: trade . event . title ,
price: trade . price ,
quantity: trade . quantity ,
type: trade . side . toUpperCase () as "YES" | "NO" ,
gainloss: calculatePL ( trade ),
status: trade . event . status === "ONGOING" ? "ACTIVE" : "PAST"
}));
} catch ( error ) {
console . error ( "Error fetching trades:" , error );
return [];
}
}
Real-time updates
Portfolio values update automatically via WebSocket:
useEffect (() => {
const ws = new WebSocket ( 'ws://server-url' );
// Subscribe to price updates for all active events
activeTrades . forEach ( trade => {
ws . send ( JSON . stringify ({
eventId: trade . eventId
}));
});
ws . onmessage = ( message ) => {
const data = JSON . parse ( message . data );
// Update trade P&L based on new prices
setActiveTrades ( prevTrades =>
prevTrades . map ( trade => {
if ( trade . eventId === data . eventId ) {
const newPrice = trade . type === "YES"
? data . orderBook . topPriceYes
: data . orderBook . topPriceNo ;
return {
... trade ,
gainloss: ( newPrice - trade . price ) * trade . quantity
};
}
return trade ;
})
);
};
return () => ws . close ();
}, [ activeTrades ]);
Portfolio analytics
Win rate
Average profit
Average loss
Total P&L
Calculate your historical win percentage: const winRate = ( winningTrades / totalTrades ) * 100 ;
const winningTrades = pastTrades . filter (
trade => trade . gainloss > 0
). length ;
const totalTrades = pastTrades . length ;
Track average gain per winning trade: const avgProfit = pastTrades
. filter ( trade => trade . gainloss > 0 )
. reduce (( sum , trade ) => sum + trade . gainloss , 0 ) / winningTrades ;
Monitor average loss per losing trade: const avgLoss = pastTrades
. filter ( trade => trade . gainloss < 0 )
. reduce (( sum , trade ) => sum + trade . gainloss , 0 ) / losingTrades ;
Sum of all realized gains and losses: const totalPL = pastTrades . reduce (
( sum , trade ) => sum + ( trade . gainloss || 0 ),
0
);
Best practices
Review regularly Check your portfolio daily to stay informed about your positions and market movements.
Set exit targets Decide profit targets and stop-losses before placing trades to maintain discipline.
Diversify Spread risk across multiple events rather than concentrating in one market.
Track patterns Analyze your past trades to identify winning strategies and avoid repeating mistakes.
Troubleshooting
Trade not appearing in portfolio
Possible reasons:
Order hasn’t matched yet (check order book)
Database sync delay (refresh after 30 seconds)
Order was canceled
Check your wallet for locked balance to verify if order is pending.
Incorrect P&L calculation
Verify:
Entry price is average across all fills
Current market price is from most recent WebSocket update
Quantity includes all matched portions
Hard refresh the page to re-sync data.
Common causes:
Insufficient liquidity at current price
Event has closed (trading ended)
WebSocket disconnected (reconnect)
Try refreshing the page and attempting again.
Past trade missing gain/loss
This happens when:
Event settlement is still pending
Database hasn’t updated yet
Manual intervention needed for outcome
Gains are credited once event status changes to SETTLED.
Next steps