Futures
Access hundreds of perpetual contracts
TradFi
Gold
One platform for global traditional assets
Options
Hot
Trade European-style vanilla options
Unified Account
Maximize your capital efficiency
Demo Trading
Introduction to Futures Trading
Learn the basics of futures trading
Futures Events
Join events to earn rewards
Demo Trading
Use virtual funds to practice risk-free trading
Launch
CandyDrop
Collect candies to earn airdrops
Launchpool
Quick staking, earn potential new tokens
HODLer Airdrop
Hold GT and get massive airdrops for free
Pre-IPOs
Unlock full access to global stock IPOs
Alpha Points
Trade on-chain assets and earn airdrops
Futures Points
Earn futures points and claim airdrop rewards
Promotions
AI
Gate AI
Your all-in-one conversational AI partner
Gate AI Bot
Use Gate AI directly in your social App
GateClaw
Gate Blue Lobster, ready to go
Gate for AI Agent
AI infrastructure, Gate MCP, Skills, and CLI
Gate Skills Hub
10K+ Skills
From office tasks to trading, the all-in-one skill hub makes AI even more useful.
GateRouter
Smartly choose from 40+ AI models, with 0% extra fees
Polymarket PnL Accurate Calculation: Why Your Profit and Loss Might Be Incorrect?
I have been developing automated trading on Polymarket for half a year, and the biggest pitfall I’ve encountered is not strategy failure, but that I couldn’t even accurately calculate how much I made or lost.
It’s not that I’m bad at it. It’s that PM’s PnL calculation itself is a minefield. The numbers provided by the official API are wrong, and the rankings displayed on third-party analysis sites are also incorrect. You write your own scripts to calculate? Most likely, they’re still wrong.
How big is the deviation? The third-place address, kch123, calculated a loss of $3.5 million using incorrect methods, but the actual profit was $11.4 million. It’s not just a few percentage points off — the profit and loss signs are reversed.
This article breaks down every pitfall I’ve fallen into. Traders, tool developers, ranking viewers — you will encounter these sooner or later.
Pit 1: cashPnl Does Not Include Settled Profits and Losses
The most intuitive approach: call the /positions API, sum up the cashPnl (cash profit and loss) fields.
Testing the top 3 addresses on the leaderboard:
swisstony: Sum of cashPnl +$35k, actual leaderboard +$5.6 million, a difference of 158 times
kch123: Sum of cashPnl -$3.52 million, actual leaderboard +$11.4 million, sign reversed
gmanas: Sum of cashPnl -$2.64 million, actual leaderboard +$5.02 million, sign reversed
For these three addresses, two of the profit/loss signs are directly reversed.
Reason: The cashPnl returned by the /positions API does not include realized PnL from closed/redeemed positions. When winning positions are automatically redeemed for USDC, that position disappears from the API response. What remains are unsettled positions — often showing unrealized losses.
You think you’re calculating total profit and loss, but you’re only getting the unsettled part.
Pit 2: makerPnl Field Is Inconsistent with On-Chain Cash Flows
The JSONL data for trades has a makerPnl (market maker profit and loss) field, which sounds like it’s for calculating PnL. Don’t trust it.
In market-making data, I observed that the sum of makerPnl calculated from the data differs by an order of magnitude from the on-chain cash flow calculations. The exact multiple varies depending on the scenario, but the direction is consistent: the internal logic of makerPnl doesn’t match the actual USDC flow.
No matter how big the deviation, the conclusion is the same: don’t use this field to calculate PnL.
Pit 3: Don’t Deduplicate by txHash Alone
This is the most counterintuitive.
Multiple records with the same txHash (transaction hash) appear. The normal reaction: duplicate data, remove duplicates.
Don’t do that. PM’s CLOB (on-chain limit order book) can match multiple maker orders within a single transaction. Multiple records under the same txHash are real, independent fills.
I previously deduplicated by txHash + asset, which caused me to undercount $133 on the buy side. On the Polygon chain, I verified that a single transaction hash indeed has multiple independent USDC transfer events, each corresponding to a real trade.
Conclusion: don’t deduplicate by txHash alone. To calculate PnL, sum directly from the raw /activity data.
Pit 4: Pagination with offset Has a Limit
Using offset for pagination in /activity? Exceeding 3,000 causes a 400 error. It’s not documented.
All three addresses verified: GET /activity?offset=3100 returns HTTP 400, with the message “max historical activity offset of 3000 exceeded.” Heavy traders often have tens of thousands of transactions, so 3,000 isn’t enough.
Using the end parameter (passing the timestamp of the last record from the previous page minus 1) as a cursor for pagination has no limit.
Pit 5: Differences in Leaderboard PnL Definitions
After calculating a single address’s PnL, comparing it to the leaderboard shows a small discrepancy.
Most of the time, the difference is within $10 (due to real-time fluctuations in position value). But if the difference is significantly larger, possible reasons include: the aggregation window of the leaderboard, cache refresh delays, or users binding multiple proxy wallets.
In testing, the PnL calculated via cash flow closely matches the lb-api response. If your results differ greatly, first check whether pagination is complete (Pit 4), and whether you used the correct fields (Pit 1-2).
Correct Approach
After trying various methods, I verified that the most reliable way is to use the Data API’s cash flow summation. No pre-calculated fields, just calculate fund inflows and outflows directly from raw transaction records.
Formula:
PnL = SUM(TRADE where side=SELL) + SUM(REDEEM) + SUM(MERGE) + SUM(MAKER_REBATE) + SUM(REWARD) - SUM(TRADE where side=BUY) - SUM(SPLIT) + Position Market Value
· TRADE BUY: Spend USDC to buy tokens (expenditure)
· TRADE SELL: Sell tokens to recover USDC (income)
· REDEEM: Redeem winning positions for USDC (income)
· SPLIT: Mint USDC into token pairs (expenditure)
· MERGE: Merge token pairs back into USDC (income)
· MAKER_REBATE: Maker rebates (income)
· REWARD: Rewards/airdrops (income)
· Data source:
GET /activity?user=
&limit=500, paginate with end, sum by type after full retrieval.· Position Market Value:
GET /positions?user=
, size × currentPrice.· Cross-Verification:
Compare the calculation results with the Polymarket leaderboard API (lb-api.polymarket.com/profit?window=all&address=X). If the difference is less than <$10, it’s acceptable. Variations come from real-time fluctuations in position value.
Verification: Top 15 addresses tested
After using the cash flow method, cross-verify with the leaderboard API:
swisstony: Cash flow method +$35k, leaderboard +$5.6M, difference < $10
kch123: Cash flow method +$5.6M, leaderboard +$11.4M, difference < $10
gmanas: Cash flow method +$11.4M, leaderboard +$5.02M, difference < $10
All three addresses have discrepancies within $10, with differences due to real-time fluctuations in position value.
Once the method is validated, I used it to analyze the real profit and loss of hundreds of top addresses. That’s a different story.
Summary
SUM(cashPnl) from /positions → Not reliable, does not include settled profits, signs may reverse
Sum of makerPnl field → Not reliable, inconsistent with on-chain cash flows
Deduplicating by txHash and then calculating → Not reliable, over $100, but removes real fills
Offset pagination + summation → Not reliable, data truncated, errors over 3,000
Data API cash flow method → Currently the most reliable, <$10
The first step in quant trading isn’t finding alpha. It’s confirming that your calculations are correct.
All of the above are based on real-world pitfalls, not theoretical deductions. PM’s API behavior may change at any time, so it’s recommended to regularly cross-verify your results with the leaderboard API.
Click to learn about the Rhythm at BlockBeats and current job openings
Join the official BlockBeats community:
Telegram subscription group: https://t.me/theblockbeats
Telegram discussion group: https://t.me/BlockBeats_App
Twitter official account: https://twitter.com/BlockBeatsAsia