Skip to content

Trade History & Portfolio ​

Base URL: https://service.leverup.xyz

Trade history ​

Every protocol event affecting a trader, decoded and joined against the position it belongs to. This is the easiest way to build an activity feed without replaying onchain logs.

http
GET /v1/user/{user_address}/trade/history
ParameterDefaultNotes
page0
size10
block_chainMONAD

Response ​

json
{
  "content": [
    {
      "id": "…",
      "transactionHash": "0x…",
      "blockNumber": 1234567,
      "transactionIndex": 3,
      "logIndex": 7,
      "hash": "0x…",
      "positionHash": "0x…",
      "pairBase": "0xcf5a…",
      "qty": "10000000",
      "entryPrice": "100123450000000000000000",
      "closePrice": null,
      "pnl": null,
      "tradeType": "MARKET",
      "operationType": "OPEN_POSITION",
      "blockTime": "2026-07-27T10:00:00Z",
      "isLong": true,
      "tokenIn": "0x7547…",
      "lvToken": "0xfd44…",
      "amountIn": "10000000",
      "margin": "9930000000000000000",
      "tokenInPrice": "1000000000000000000",
      "position": { },
      "detail": { }
    }
  ],
  "pageNumber": 0,
  "pageSize": 10,
  "totalPages": 12,
  "totalElements": 116
}

position embeds the same object returned by Positions, so a single history page gives you both the event and the position state.

Units follow the onchain conventions: qty at 1e10, entryPrice / closePrice at 1e18, amountIn in tokenIn decimals, and margin / pnl in lvToken decimals. See Precision & Units.

operationType ​

Each value corresponds to the onchain event of the same name — see Events.

GroupValues
OpeningMARKET_PENDING_TRADE, OPEN_POSITION, POSITION_INCREASED, PENDING_TRADE_REFUND
ClosingCLOSE_POSITION, POSITION_DECREASED, EXECUTE_CLOSE_SUCCESSFUL, EXECUTE_CLOSE_REJECTED
Limit ordersOPEN_LIMIT_ORDER, EXECUTE_LIMIT_ORDER_SUCCESSFUL, EXECUTE_LIMIT_ORDER_REJECTED, CANCEL_LIMIT_ORDER, LIMIT_ORDER_REFUND, UPDATE_ORDER_TP, UPDATE_ORDER_SL
TP/SL ordersDECREASE_ORDER_CREATED, DECREASE_ORDER_UPDATED, DECREASE_ORDER_CANCELLED, EXECUTE_DECREASE_ORDER_SUCCESSFUL
Position managementUPDATE_MARGIN, UPDATE_TRADE_TP, UPDATE_TRADE_SL

Older records may carry OPEN_MARKET_TRADE and CLOSE_TRADE_SUCCESSFUL from the pre-merge event model. Treat them as equivalent to OPEN_POSITION and CLOSE_POSITION when rendering history.

ts
async function activityFeed(address: string) {
  const res = await fetch(`${API}/v1/user/${address}/trade/history?size=50`)
  const { content } = await res.json()

  return content.map((e: any) => ({
    at: e.blockTime,
    what: e.operationType,
    pair: e.position?.pair ?? e.pairBase,
    tx: e.transactionHash,
  }))
}

Current unrealized PnL ​

Returns the current USD valuation of all of a trader's POOL positions on Monad, including legacy and merged positions. This is an account total, with no pagination or time-range filter. Cross-Exchange positions are excluded.

http
GET /v1/portfolio/{user_address}/unrealized-pnl?block_chain=MONAD
ParameterLocationRequiredNotes
user_addressPathyesA valid EVM wallet address; returned lowercase
block_chainQuerynoDefaults to MONAD; use this spelling, not blockchain

No authentication or wallet signature is required. Mainnet example (replace the address with the wallet you want to query):

bash
curl --fail-with-body \
  'https://service.leverup.xyz/v1/portfolio/0x0000000000000000000000000000000000000001/unrealized-pnl?block_chain=MONAD'

Response fields ​

All four monetary fields are decimal USD strings: "12.5" means $12.50, not a scaled integer. Do not divide them by 1e18. Keep strings or use decimal arithmetic when calculating with these values; see Precision & Units.

FieldTypeMeaning
userAddressstringLowercase wallet address
blockChainstringMONAD
positionCountintegerNumber of onchain positions included
unrealizedPnlUsdstringMark-to-market PnL, with each position's loss capped at its margin
unrealizedPnlAfterAccruedFeesUsdstringPnL including accrued funding and holding fees, capped independently per position
fundingFeeUsdstringTotal funding: positive is income, negative is an expense
holdingFeeUsdstringTotal accrued holding expense, reported as a nonnegative amount
blockNumberstringBlock used to read positions and their accrued fees
blockTimestampintegerTimestamp of that block, in Unix seconds
priceAsOfinteger, null or absentEarliest publication time among the quotes used, in Unix seconds; null or omitted for an empty account

Illustrative response:

json
{
  "userAddress": "0x0000000000000000000000000000000000000001",
  "blockChain": "MONAD",
  "positionCount": 1,
  "unrealizedPnlUsd": "10",
  "unrealizedPnlAfterAccruedFeesUsd": "12",
  "fundingFeeUsd": "3",
  "holdingFeeUsd": "1",
  "blockNumber": "108450856",
  "blockTimestamp": 1790507755,
  "priceAsOf": 1790507755
}

With no positions, positionCount is 0 and all monetary fields are "0". The response still includes the current position-snapshot block; priceAsOf is null or omitted. A failed query is not an empty account.

Valuation and fees ​

For each position, the service calculates signed PnL from its quantity, entry price and current mark price, then values the result using its settlement token (marginToken). The loss floor is that position's margin. In settlement-token units, before conversion to USD:

text
gross = max(rawPnl, -margin)
net   = max(rawPnl + fundingFee - holdingFee, -margin)

The two floors are applied independently before summing the USD totals. Consequently, unrealizedPnlAfterAccruedFeesUsd cannot always be reconstructed by adding the aggregate funding and holding amounts to the already-capped unrealizedPnlUsd. Integer rounding can also leave tiny differences.

Accrued fees are already included; do not add them again. Paid opening fees are not deducted again, and the net field excludes estimated closing fees, execution fees and slippage. It is a current valuation, not a guaranteed amount receivable on closing. Realized PnL from Portfolio data and Trading stats is separate.

Freshness, caching and errors ​

Positions and accrued fees are read from one onchain block. Quotes are fetched separately, so blockTimestamp and priceAsOf need not be equal. The endpoint does not wait for the historical statistics publication window.

Successful responses carry Cache-Control: no-store. The current freshness limit for both the position snapshot and quotes is 30 seconds, with up to 5 seconds of future clock skew; valuation has a 10-second processing timeout. Client/network latency is additional. A recently retrieved DEX quote can still have an old publication time and be rejected, including when a market has stopped publishing fresh prices.

StatusMeaningClient handling
200Complete valuation, including an empty accountDisplay the returned decimal USD amounts
400Invalid address or invalid chain parameterCorrect the request
503Complete current valuation unavailable: RPC failure/timeout, missing token information, missing/nonpositive/stale quotes, or an explicitly unsafe quoteShow an unavailable state and retry with backoff; do not substitute zero or a partial total

One unavailable position or required quote causes the entire valuation to fail. Optional price safety signals are honored when supplied; a successful response does not mean every provider supplied an independent safety verdict. Clients should branch on the HTTP status rather than matching error-message text.

Trade overview ​

Headline PnL numbers for a trader.

http
GET /v1/portfolio/{user_address}/trade_overview?timeframe=DAYS_30&is_after_fee=true
ParameterRequiredNotes
timeframeyesALL_TIME, DAYS_7, DAYS_30, DAYS_60
is_after_feeyesWhether PnL is net of fees
blockchainnoDefaults to MONAD
json
{
  "realizedPnlUsd": "1234.56",
  "biggestWinUsd": "890.12",
  "winRate": 0.62,
  "updatedAt": "2026-07-27T10:00:00Z"
}

winRate is a fraction, not a percentage. Cached for 30 seconds.

PnL chart ​

Time series for a PnL chart.

http
GET /v1/portfolio/{user_address}/pnl_chart_data?timeframe=DAYS_30&is_after_fee=true&timezone=UTC
ParameterRequiredNotes
timeframeyesALL_TIME, DAYS_7, DAYS_30, DAYS_60
is_after_feeyes
timezoneyesDetermines day boundaries, e.g. UTC, Asia/Shanghai
blockchainno
json
{
  "data": [
    { "t": 1785225600, "pnl": "120.50" },
    { "t": 1785312000, "pnl": "-45.20" }
  ],
  "updatedAt": "2026-07-27T10:00:00Z",
  "resolution": "DAY_1"
}

t is a Unix second bucket start. resolution is DAY_1, DAY_7 or DAY_30, chosen by the server based on the timeframe. Cached for 30 seconds.

Portfolio data ​

Aggregate breakdown across markets.

http
GET /v1/portfolio/{user_address}/portfolio_data
json
{
  "trader": "0x…",
  "realizedPNL": "1500000000000000000000",
  "realizedPNLAfterFees": "1234560000000000000000",
  "tradingVolumeUSD": "250000000000000000000000",
  "gain": 31,
  "loss": 19,
  "metrics": {
    "positionLiveCount": 2,
    "orderLiveCount": 1
  },
  "tradingPairs": [
    {
      "pairBase": "0xcf5a…",
      "pairName": "BTC/USD",
      "pairSymbol": "BTC",
      "pairType": "CRYPTO",
      "tradingVolumeQty": "125000000000",
      "tradingVolumeUSD": "180000000000000000000000"
    }
  ]
}

realizedPNL, realizedPNLAfterFees and tradingVolumeUSD are USD scaled by 1e18; tradingVolumeQty is base-asset quantity scaled by 1e10. These units differ from the already decimal USD amounts in Current unrealized PnL. See Precision & Units.

gain and loss are counts of profitable and unprofitable closed positions.

Trading perpetuals involves risk. Nothing here is financial advice.