Documentation Index
Fetch the complete documentation index at: https://docs.clicker.xyz/llms.txt
Use this file to discover all available pages before exploring further.
This guide shows how to combine them to derive current value, unrealized PnL, and percent change for both spot and perp positions.
Philosophy
Your app likely its own high-performance system for live prices. (If not, we can recommend pricing APIs for you.) For that reason, the Clicker API only returns historical data: cost basis, realized PnL, and position amounts. You bring your own live price data to these calculations.
These fields can be found in metadata and metadata.positionStats of a HydratedPosition.
Detecting Spot vs Perps
Check metadata.perpPositionType. If it’s "long" or "short", the position is a perp. If it’s null or absent, it’s spot.
For Hyperliquid positions, you can also check for the presence of positionAmountWithLeverage.
Spot Positions
Current Value
currentValue = positionAmount * currentPrice
| Field | Source |
|---|
positionAmount | metadata.positionAmount |
currentPrice | Your pricing feed |
Unrealized PnL
costBasis = holdingsCostBasisUSD + holdingReceivedCostBasisUSD
unrealizedPnL = currentValue - costBasis
| Field | Source |
|---|
holdingsCostBasisUSD | metadata.positionStats.holdingsCostBasisUSD |
holdingReceivedCostBasisUSD | metadata.positionStats.holdingReceivedCostBasisUSD |
holdingsCostBasisUSD is the cost basis of tokens the trader bought. holdingReceivedCostBasisUSD is the cost basis of tokens the trader received via airdrops or transfers, valued at market price at the time of receipt. Together they form the full cost basis of current holdings.
Total PnL
To show total PnL (realized + unrealized):
totalPnL = realizedGainsUSD + unrealizedPnL
realizedGainsUSD captures profit or loss from tokens already sold.
Percent Change
totalInvested = boughtUSD + receivedCostBasisUSD
percentChange = (totalPnL / totalInvested) * 100
| Field | Source |
|---|
boughtUSD | metadata.positionStats.boughtUSD |
receivedCostBasisUSD | metadata.positionStats.receivedCostBasisUSD |
Only compute percent change when totalInvested >= 1. Below that threshold, the percentage is meaningless.
Example
A trader bought 10,000 tokens at $0.05 for $500. The token is now $0.08.
currentValue = 10000 * 0.08 = $800
costBasis = 500 + 0 = $500
unrealizedPnL = 800 - 500 = $300
totalPnL = 0 + 300 = $300 (no realized gains yet)
percentChange = (300 / 500) * 100 = 60%
Perp Positions
Perps use leveraged values for PnL and margin (collateral) for position value.
Unrealized PnL
Compute the current leveraged notional value:
leveragedNotionalValue = abs(positionAmountWithLeverage) * currentPrice
Then compute PnL based on direction:
// Long
unrealizedPnL = leveragedNotionalValue - holdingsCostBasisUSDWithLeverage
// Short
unrealizedPnL = holdingsCostBasisUSDWithLeverage - leveragedNotionalValue
| Field | Source |
|---|
positionAmountWithLeverage | metadata.positionAmountWithLeverage |
holdingsCostBasisUSDWithLeverage | metadata.positionStats.holdingsCostBasisUSDWithLeverage |
Current Value (Equity)
For perps, the position value is the trader’s equity: margin plus unrealized PnL.
margin = holdingsCostBasisUSD
currentValue = abs(margin + unrealizedPnL)
holdingsCostBasisUSD on a perp position represents the margin (collateral) posted, not the full notional exposure.
Total PnL
totalPnL = realizedGainsUSD + unrealizedPnL
Percent Change
totalInvested = boughtUSD + receivedCostBasisUSD
percentChange = (totalPnL / totalInvested) * 100
Same formula as spot. boughtUSD on a perp is the total margin posted across all entries.
Example
A trader opens a 5x long on ETH at $3,000 with $1,000 margin. ETH is now $3,300.
positionAmountWithLeverage = 1.6667 (5000 / 3000)
holdingsCostBasisUSDWithLeverage = $5,000
holdingsCostBasisUSD (margin) = $1,000
leveragedNotionalValue = 1.6667 * 3300 = $5,500
unrealizedPnL = 5500 - 5000 = $500
currentValue = abs(1000 + 500) = $1,500
totalPnL = 0 + 500 = $500
percentChange = (500 / 1000) * 100 = 50%
The 10% move in ETH produced a 50% return because of 5x leverage.
Closed Positions
A position is closed when the trader has exited entirely. For closed positions, there is no unrealized PnL to compute. Display realizedGainsUSD as the total PnL and compute percent change against totalInvested as above.
totalPnL = realizedGainsUSD
percentChange = (realizedGainsUSD / totalInvested) * 100
You can detect a closed position by checking metadata.positionStats.isOpen === false, or by checking that the position’s remaining value is below $1 (the dust threshold).
TL;DR Calculation
function calculatePosition(
metadata: HydratedPosition["metadata"],
currentPrice: number,
) {
const { positionStats: stats } = metadata;
const isPerp =
metadata.perpPositionType === "long" ||
metadata.perpPositionType === "short";
// Unrealized PnL
const notionalValue =
Math.abs(
isPerp ? metadata.positionAmountWithLeverage : metadata.positionAmount,
) * currentPrice;
const costBasis = isPerp
? stats.holdingsCostBasisUSDWithLeverage
: stats.holdingsCostBasisUSD + stats.holdingReceivedCostBasisUSD;
const unrealizedPnL =
metadata.perpPositionType === "short"
? costBasis - notionalValue
: notionalValue - costBasis;
// Current value, total PnL, percent change
const currentValue = isPerp
? Math.abs(stats.holdingsCostBasisUSD + unrealizedPnL)
: notionalValue;
const totalPnL = stats.realizedGainsUSD + unrealizedPnL;
const totalInvested = stats.boughtUSD + stats.receivedCostBasisUSD;
const percentChange =
totalInvested >= 1 ? (totalPnL / totalInvested) * 100 : undefined;
return { currentValue, unrealizedPnL, totalPnL, percentChange };
}