Overview
The Profile Analysis endpoint aggregates user profile + portfolio data into a single payload for bots, dashboards, and LLM workflows. This page documents the exact calculation logic used by the API so users can verify every metric.This endpoint is designed for MCP (Model Context Protocol) tools and AI agents.
Values are rounded for display in the API response, but formulas below describe the source calculations.
Endpoint
/v1/account/profile-analysis
Full profile analysis with all metrics
Query Parameters
integer
default:"20"
Number of recent trades to include (1-100)
integer
default:"90"
Days of equity history to analyze (1-365)
integer | 'all' | 'api'
default:"api"
Wallet scope for the whole analysis — positions, trading stats, risk
metrics, snapshots, recent trades, cash basis and PnL baseline alike. An
integer scopes to a single wallet you own (404
WALLET_NOT_FOUND
otherwise); api scopes to your API wallet (including legacy rows recorded
before per-wallet attribution); all restores the cross-wallet blended
view. Keywords are case-insensitive; any other value returns 422
VALIDATION_FAILED. Omitted = api.Authentication
API key only —X-API-Key: <key> (or the PM-compat POLY_API_KEY /
Authorization: Bearer ps_live_... aliases). A Supabase Bearer JWT is not
accepted here.
Errors
All errors return{"error": "<CODE>", "message": "<human-readable>"}.
Response
The top level also carriesanalysis_generated_at (ISO-8601 UTC string),
analysis_version (string, currently "1.0.0"), and a natural_language_summary
string, alongside these sections:
profile — User Metadata
balance — Balance Summary
trading_stats — Trading Statistics
risk_metrics — Risk Analysis
How Metrics Are Calculated
Balance and PnL
- Total portfolio value =
api_balance + total_position_value(both scoped to the selected wallet — the API wallet by default) - UI PnL =
ui_balance - starting_ui_balance(UI baseline = seed + topups + grants) - API PnL =
total_portfolio_value - starting_api_balance - UI PnL % =
ui_pnl / starting_ui_balance * 100 - API PnL % =
api_pnl / starting_api_balance * 100
starting_api_balance is the scoped wallet’s actual starting_balance
(tier-aware: Pro 25,000 for the API wallet; a specific
wallet’s own baseline when wallet_id=<id>), so api_pnl here agrees with
GET /v1/account/balance and GET /v1/account/portfolio for the same
wallet. Before 2026-06-10 this endpoint used a fixed $10,000 baseline
regardless of tier — that caveat no longer applies.
Open Position Valuation
For each open position:- Cost basis =
avg_entry_price * quantity - Market value =
current_price * quantity(if live price exists) - If no live price is available, cost basis is used as fallback valuation.
- Unrealized PnL (position) =
market_value - cost_basis - Unrealized PnL (account) =
sum(open_position_market_values) - sum(open_position_cost_basis)
Realized PnL (Closed Positions)
Closed positions in storage havequantity = 0, so realized PnL is reconstructed from filled orders.
For each (market_id, outcome) closed position:
buy_notional = sum(BUY order notionals)sell_notional = sum(SELL order notionals)buy_qty = sum(BUY order quantities)sell_qty = sum(SELL order quantities)remaining_qty = buy_qty - sell_qtysettlement_value = exit_price * remaining_qty- position_realized_pnl =
sell_notional + settlement_value - buy_notional
- realized_pnl =
sum(position_realized_pnl over closed positions)
Win Rate and Win/Loss Counts
Win/loss is based on realized PnL sign, not on price comparison alone:- Win:
position_realized_pnl > 0 - Loss:
position_realized_pnl < 0 - Break-even:
position_realized_pnl == 0(excluded from win/loss counts)
win_rate uses closed position count as denominator:
- win_rate =
wins / total_closed_positions * 100
Profit Factor and Trade PnL Stats
- Gross profit =
sum(all positive position_realized_pnl) - Gross loss =
sum(abs(all negative position_realized_pnl)) - profit_factor =
gross_profit / gross_loss(when gross_loss > 0) - best_trade_pnl = max positive closed-position PnL
- worst_trade_pnl = min negative closed-position PnL
- avg_win_pnl = average of positive closed-position PnLs
- avg_loss_pnl = average of negative closed-position PnLs
Drawdown (7d and 30d)
Drawdown is computed fromportfolio_snapshots.total_value using a running peak:
- Walk snapshots in chronological order
- Track highest value seen so far (
peak) - Compute drawdown each point:
(value - peak) / peak - Maximum drawdown = most negative drawdown in the period
Portfolio Diversity and Concentration
For each open position:- Effective value =
market_value(live price × quantity) when a live price exists, orcost_basis(entry price × quantity) as fallback when no live price is available. - Weight per position:
w_i = effective_value / total_invested - HHI =
sum(w_i^2) - portfolio_diversity_score =
1 - HHI - largest_position_weight = largest
w_i - top_3_concentration = sum of top 3
w_i
Equity Returns
Using snapshots in the requestedequity_days window:
return_7d: first-to-last return among snapshots in last 7 daysreturn_30d: first-to-last return among snapshots in last 30 daysreturn_all_time: first-to-last return across the fullequity_dayswindow
- period_return =
(end_value - start_value) / start_value * 100
null.
Data Scope and Semantics
- Wallet scope: every section —
open_positions,trading_stats,risk_metrics,equity_timeline,category_exposure,recent_tradesand thebalancecash/baseline — covers the wallet selected bywallet_id(the API wallet when omitted; positions/orders recorded before per-wallet attribution count toward the API wallet).wallet_id=allspans every wallet you own. Onlyui_balance/ui_pnlare always MAIN-wallet metrics regardless of scope. open_positionscontains onlystatus=OPENwithquantity > 0- Trading stats and realized metrics use only filled orders
- Category exposure is based on open-position values
- Cash/invested percentages are relative to current total portfolio value
equity_timeline — Performance Timeline
category_exposure — Category Breakdown
Array of objects showing exposure per market category:
recent_trades — Recent Filled Orders
Array of the most recent filled orders (count controlled by the
recent_trades query param, default 20). Each entry:
See Trade History for the full per-trade semantics.
natural_language_summary
A pre-computed human-readable summary of the profile:
“trader123 is a PolySimulator paper trader who joined 45 days ago. Current API balance: 10,000.00, P&L: -1,100.00. Top categories: crypto (45.5%), sports (27.3%), politics (18.2%).”