{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/0xinsider-com/json-schema/0xinsider-com-trader-context-schema.json",
  "title": "TraderContext",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/0xinsider-com-openapi.json#/components/schemas/TraderContext",
  "type": "object",
  "required": [
    "trader",
    "data_as_of",
    "freshness_note"
  ],
  "properties": {
    "trader": {
      "$ref": "#/$defs/Trader"
    },
    "position_summary": {
      "type": "object",
      "description": "Aggregate position and P&L coverage for the trader, over its synced markets. Since 2026-10-27 (#29366) a wallet that holds a sports or esports market has only sports and esports markets synced, so markets_synced, markets_resolved, markets_open, unrealized_mtm, cost_basis_locked and the resolved win figures cover those markets; before, they covered every Polymarket market. A wallet with no sports or esports market can still carry older markets of other categories until they are deleted. markets_total, total_realized_pnl and synced_realized_pnl still cover every Polymarket market of the wallet. Omitted entirely (key absent, never null) when the trader is not in the local database or native net economics is unavailable. Realized fields remain numbers when present, including a genuine zero.",
      "required": [
        "markets_total",
        "markets_synced",
        "markets_pruned",
        "markets_unstored",
        "markets_combo",
        "markets_resolved",
        "markets_open",
        "sync_coverage",
        "synced_realized_pnl",
        "total_realized_pnl",
        "unrealized_mtm",
        "cost_basis_locked",
        "resolved_win_rate",
        "resolved_wins",
        "resolved_decided",
        "as_of"
      ],
      "properties": {
        "markets_total": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Polymarket's count of the markets the wallet traded, every category, when known; null when the provider total is unavailable."
        },
        "markets_synced": {
          "type": "integer",
          "description": "Markets with locally synced position rows."
        },
        "markets_pruned": {
          "type": "integer",
          "description": "Markets outside sports and esports that the wallet traded and whose synced rows 0xinsider deleted, counted when they were deleted (from 2026-10-27, #29366); 0 when none were. Not in markets_synced or any other count here; sync_coverage adds it to markets_synced so both sides of that ratio count every category."
        },
        "markets_unstored": {
          "type": "integer",
          "description": "Markets outside sports and esports that the wallet first traded since 2026-10-26, which 0xinsider does not store, counted as the wallet syncs (#30165); 0 when none are. Not in markets_synced, markets_pruned or any other count here; sync_coverage adds it with markets_pruned to markets_synced."
        },
        "markets_combo": {
          "type": "integer",
          "description": "Combo markets the wallet traded, as maker or taker, counted from the combo fills 0xinsider indexes from the chain (#30218); 0 when it traded none. Polymarket counts each combo as one market in markets_total, and no position read lists one, so a combo is in no other count here; sync_coverage adds it with markets_pruned and markets_unstored to markets_synced."
        },
        "markets_resolved": {
          "type": "integer",
          "description": "Synced markets that have resolved."
        },
        "markets_open": {
          "type": "integer",
          "description": "Synced markets still open with residual value (open positions with current value > 0)."
        },
        "sync_coverage": {
          "type": "number",
          "description": "markets_synced plus markets_pruned plus markets_unstored plus markets_combo, divided by markets_total when the provider total is known (capped at 1.0); 0.0-1.0. Both sides count every category: no Polymarket count of a wallet's sports and esports markets exists, so the ratio does not estimate one. When markets_total is unknown or not positive (null, 0, or negative), this is 1.0 if that sum is positive (else 0.0), so cross-check markets_total before treating 1.0 as full coverage."
        },
        "synced_realized_pnl": {
          "type": "number",
          "description": "Native net realized P&L (USD) over every Polymarket market of the wallet, including credited rebates, minus the stored realized component of synced open positions with positive current value. Rebates are credited to the account, not to a position, so every credited rebate stays in this figure. NUMERIC arithmetic precedes conversion to a JSON number."
        },
        "total_realized_pnl": {
          "type": "number",
          "description": "Native net realized P&L (USD) over every Polymarket market of the wallet, including credited rebates, read directly from the accounting snapshot. For the sports and esports figure read trader.pnl.in_scope.realized_pnl. Position sync_coverage is separate from this accounting basis."
        },
        "unrealized_mtm": {
          "type": "number",
          "description": "Mark-to-market unrealized P&L (USD) on open positions in synced markets."
        },
        "cost_basis_locked": {
          "type": "number",
          "description": "Cost basis (USD) currently tied up in open positions in synced markets."
        },
        "resolved_win_rate": {
          "type": [
            "number",
            "null"
          ],
          "description": "Win rate as a percentage (0-100): resolved_wins over resolved_decided. A resolved market that settled at exactly zero realized P&L (a void, a refund, a fully hedged position) is neither a win nor a loss and is not in the denominator, the same rule the leaderboard applies; null when no resolved market was decided. It is the rule of trader.stats.win_rate, read from the synced rows at request time; stats.win_rate is the stored figure the profile shows, refreshed by each sync and a few minutes after a closed-history write. context.md prints one Market win rate, stats.win_rate."
        },
        "resolved_wins": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Resolved markets that settled at positive realized P&L: the win-rate numerator. Additive; null only on a summary cached before the field existed."
        },
        "resolved_decided": {
          "type": [
            "integer",
            "null"
          ],
          "description": "Resolved markets that settled at a non-zero realized P&L: the win-rate denominator. At most markets_resolved; the difference is markets settled at exactly zero or with an unknown P&L. Additive; null only on a summary cached before the field existed."
        },
        "as_of": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time",
          "description": "RFC3339 freshness of the served OPEN-position data: the trader's latest /positions snapshot, else the last completed sync. The snapshot advances ONLY open positions, so read this as the open-position freshness clock -- the resolved/closed aggregates on this same summary (markets_resolved, resolved_win_rate) advance only on a full sync. The value is the /positions snapshot instant when one exists, so it is typically at or just before the trader-level last sync on a normal sync, and can be AFTER it while the active-view loop refreshes open positions between full syncs. This clock does not establish native accounting freshness. Always present on the wire (serialized as JSON null when the trader has neither a snapshot nor a sync); never omitted."
        }
      }
    },
    "data_as_of": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time",
      "description": "RFC3339 freshness of the OPEN-position-level data: when a position_summary is present this mirrors its as_of byte-for-byte (latest /positions snapshot, else last completed sync) -- the open-position freshness clock, since the snapshot advances only open positions; otherwise the trader's last completed sync, even if an unserved position snapshot exists. Null when the selected clock is unavailable; a missing breakdown does not establish position or accounting freshness."
    },
    "freshness_note": {
      "type": "string",
      "description": "Human-readable statement of the point-in-time snapshot semantics (data_as_of is the open-position clock -- the latest /positions snapshot, else the last completed sync; the snapshot advances only open positions, so resolved counts and win rate can include settled markets recorded after the last full sync; native realized P&L follows its accounting snapshot -- not a live feed; re-fetch for fresher data)."
    }
  },
  "$defs": {
    "CategorySkillModelReadiness": {
      "type": "object",
      "required": [
        "status",
        "model_version",
        "taxonomy_version",
        "observation_started_at",
        "as_of",
        "source_last_success_at"
      ],
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "live",
            "insufficient",
            "stale",
            "unknown",
            "degraded"
          ]
        },
        "model_version": {
          "type": "string"
        },
        "taxonomy_version": {
          "type": "string"
        },
        "observation_started_at": {
          "type": "string",
          "format": "date-time"
        },
        "as_of": {
          "type": "string",
          "format": "date-time"
        },
        "source_last_success_at": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        }
      },
      "description": "Model-wide readiness, read in the same database snapshot as category_records. Individual category rows retain their own status."
    },
    "CategorySkillV2": {
      "type": "object",
      "description": "Forward-only category evidence from observed Polymarket taker fills. Status is category eligibility, not a global letter grade or a guarantee of positive edge. Scores are probability differences. Unknown and degraded rows withhold scores. Coverage is partial; observation counts are not lifetime market counts.",
      "required": [
        "status",
        "model_version",
        "taxonomy_version",
        "platform",
        "scope",
        "source_coverage",
        "canonical_category",
        "as_of",
        "source_last_success_at",
        "observation_started_at",
        "latest_observation_at",
        "independent_event_count",
        "resolved_condition_count",
        "unresolved_observation_count",
        "edge_mean",
        "edge_sd",
        "edge_se",
        "edge_lower_95",
        "brier_event_avg"
      ],
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "live",
            "insufficient",
            "stale",
            "unknown",
            "degraded"
          ]
        },
        "model_version": {
          "type": "string"
        },
        "taxonomy_version": {
          "type": [
            "string",
            "null"
          ]
        },
        "platform": {
          "type": "string",
          "enum": [
            "polymarket"
          ]
        },
        "scope": {
          "type": "string",
          "enum": [
            "observed_goldsky_primary_taker_fill"
          ]
        },
        "source_coverage": {
          "type": "string",
          "enum": [
            "partial_whale_threshold_fills",
            "graded_wallet_fills"
          ]
        },
        "canonical_category": {
          "type": "string"
        },
        "as_of": {
          "type": "string",
          "format": "date-time"
        },
        "source_last_success_at": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        },
        "observation_started_at": {
          "type": "string",
          "format": "date-time"
        },
        "latest_observation_at": {
          "type": [
            "string",
            "null"
          ],
          "format": "date-time"
        },
        "independent_event_count": {
          "type": "integer",
          "minimum": 0
        },
        "resolved_condition_count": {
          "type": "integer",
          "minimum": 0
        },
        "unresolved_observation_count": {
          "type": "integer",
          "minimum": 0
        },
        "edge_mean": {
          "type": [
            "number",
            "null"
          ]
        },
        "edge_sd": {
          "type": [
            "number",
            "null"
          ]
        },
        "edge_se": {
          "type": [
            "number",
            "null"
          ]
        },
        "edge_lower_95": {
          "type": [
            "number",
            "null"
          ]
        },
        "brier_event_avg": {
          "type": [
            "number",
            "null"
          ]
        }
      }
    },
    "DataQuality": {
      "type": "object",
      "description": "Compact data age and coverage for a response body, always present on the operations that publish it. Read status and as_of to decide whether to use the body at all, and field_groups to see which part is weak. Everything here comes from stored observation clocks, so a cached body reports the same ages a freshly computed one does: meta.cached and meta.cache_age_s stay the only transport-time facts and neither makes this block newer. The per-field audit object is still available through expand=trust; this is the default summary of the same question.",
      "required": [
        "status",
        "field_groups"
      ],
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "fresh",
            "partial",
            "unknown",
            "untracked",
            "unavailable"
          ],
          "description": "fresh when every group is fresh, unavailable when every group is unavailable, and partial in every other case."
        },
        "as_of": {
          "type": "string",
          "format": "date-time",
          "description": "The oldest as_of among the groups that carry one: the age of the weakest clock this body rests on. Omitted when no group carries a clock."
        },
        "field_groups": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/DataQualityGroup"
          },
          "description": "One entry per field group. Entries may be added in later releases, so match on group rather than on position or length."
        }
      }
    },
    "DataQualityGroup": {
      "type": "object",
      "description": "One group of response fields that share a writer and therefore share a clock.",
      "required": [
        "group",
        "owner",
        "status"
      ],
      "properties": {
        "group": {
          "type": "string",
          "description": "Stable snake_case group name. Names are additive across releases, so match on the ones you know and ignore the rest."
        },
        "owner": {
          "type": "string",
          "description": "The table and column that write this group, named so the verdict can be audited (for example trader_rankings.computed_at)."
        },
        "status": {
          "type": "string",
          "enum": [
            "fresh",
            "partial",
            "unknown",
            "untracked",
            "unavailable"
          ],
          "description": "fresh: served, and as_of carries this group's real observation or computation clock. partial: some of the group's fields are served and some are missing. unknown: served, and this read has no clock for it, so no age may be inferred. untracked: 0xinsider does not track this group for this subject, by design. unavailable: the group could not be served. New values may be added; treat one you do not recognize as unknown. fresh means the group is tracked and clocked, not that it is inside any particular tolerance: compare as_of against your own."
        },
        "as_of": {
          "type": "string",
          "format": "date-time",
          "description": "When this group's values were observed or computed. Omitted whenever the read cannot measure it, and never filled with the serialization time, the cache time, or another group's clock."
        },
        "reason": {
          "type": "string",
          "description": "Why the status is not fresh. Omitted when it is."
        }
      }
    },
    "ExactDecimal": {
      "type": "object",
      "required": [
        "value",
        "unit",
        "scale",
        "basis"
      ],
      "description": "A lossless decimal atom rendered from the canonical NUMERIC or provider value. The value is a decimal string and must be parsed with a decimal library; it is never a display string and must not be converted through a binary float. `scale` is the source decimal scale. The field is omitted when its source is unavailable.",
      "properties": {
        "value": {
          "type": "string",
          "description": "Plain decimal text at full source precision, including a minus sign for negative values and trailing zeros when the source scale carries them. Parse as an arbitrary-precision decimal.",
          "pattern": "^-?(0|[1-9][0-9]*)(\\.[0-9]+)?$"
        },
        "unit": {
          "type": "string",
          "description": "Unit of the value, such as `USD`, `USD/share`, or `shares`."
        },
        "scale": {
          "type": "integer",
          "minimum": 0,
          "description": "Number of digits after the decimal point in `value`'s source atom."
        },
        "basis": {
          "type": "string",
          "description": "Backend-owned source or derivation basis. Treat it as provenance, not as a display label."
        }
      }
    },
    "PnlCorrection": {
      "type": "object",
      "required": [
        "basis",
        "amount",
        "as_of",
        "markets_measured"
      ],
      "description": "A derived 0xinsider correction to Polymarket's P&L, never a Polymarket value. Polymarket misbooks neg-risk conversions, in both directions: it puts cost on placeholder YES outcomes minted by a conversion and never books it as a loss (negative amount), and its position records leave out shares the wallet really got, such as YES minted by a conversion, so it books no P&L on them (positive amount). Per neg-risk market the wallet converted in, 0xinsider measures Polymarket's own activity cash against the sum of its position P&L, and sums the difference over every measured market whose shares did not move by direct transfer: transferred shares have no activity row, so such a market keeps Polymarket's figure and is counted in markets_excluded. It is published once every neg-risk market with a sports or esports event that the wallet converted in is measured and checked for transfers, and stays as last published until then; a market with no sports or esports event is not measured, and counts only when it was measured before (on the trader body, pnl.correction_pending says so); a sum under $1 either way publishes nothing. The body's own P&L fields keep Polymarket's figures; this object adds the amount and the corrected figures. Money is truncated toward zero to cents.",
      "properties": {
        "basis": {
          "type": "string",
          "enum": [
            "neg_risk_conversion_v1"
          ],
          "description": "The correction method."
        },
        "amount": {
          "type": "number",
          "description": "The correction in USD. Negative when Polymarket overstates the wallet."
        },
        "realized": {
          "type": "number",
          "description": "Polymarket's net realized P&L plus amount. Since 2026-10-22 the grade reads this figure's sports and esports share. Omitted when Polymarket's figure is."
        },
        "net_total": {
          "type": "number",
          "description": "Polymarket's net total P&L over every Polymarket market of the wallet, plus amount. Omitted when Polymarket's figure is, and on leaderboard entries."
        },
        "as_of": {
          "type": "string",
          "format": "date-time",
          "description": "The newest measurement among the measured markets."
        },
        "markets_measured": {
          "type": "integer",
          "description": "Neg-risk markets whose measurement amount sums."
        },
        "markets_excluded": {
          "type": "integer",
          "description": "Measured neg-risk markets left out because shares moved in or out of the wallet by direct transfer; they keep Polymarket's figure. Omitted when none."
        }
      }
    },
    "Trader": {
      "type": "object",
      "required": [
        "id",
        "address",
        "pnl",
        "stats",
        "data_quality"
      ],
      "properties": {
        "id": {
          "type": "string",
          "description": "Prefixed ID (trd_...)."
        },
        "address": {
          "type": "string"
        },
        "username": {
          "type": "string"
        },
        "grade": {
          "type": "string",
          "enum": [
            "S",
            "A",
            "B",
            "C",
            "D",
            "F"
          ]
        },
        "streak_tier": {
          "type": "string",
          "enum": [
            "hot",
            "rising",
            "neutral",
            "cooling",
            "cold"
          ],
          "description": "Hot-streak tier (trailing-7d cross-sectional percentile); a separate axis from the all-time grade. Omitted when there is no recent activity."
        },
        "score": {
          "type": "number"
        },
        "forecast_score": {
          "type": "number",
          "description": "Optional forecast score on the documented display scale. Null when unavailable."
        },
        "forecast_evidence": {
          "type": "number",
          "minimum": 0,
          "maximum": 1,
          "description": "Optional measured forecast context. Missing values remain unavailable rather than being inferred."
        },
        "rank": {
          "type": "integer"
        },
        "pnl": {
          "type": "object",
          "properties": {
            "total": {
              "type": "number",
              "deprecated": true,
              "x-never-sent": true,
              "description": "Deprecated since 2026-10-27 and never sent. It was Polymarket's all-time leaderboard P&L, which covered every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29830). Read pnl.in_scope.realized_pnl."
            },
            "net_total": {
              "type": "number",
              "deprecated": true,
              "x-never-sent": true,
              "description": "Deprecated since 2026-10-27 and never sent. It was Polymarket's net total P&L over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29830). Read pnl.in_scope.realized_pnl."
            },
            "correction": {
              "$ref": "#/$defs/PnlCorrection",
              "deprecated": true,
              "x-never-sent": true,
              "description": "Deprecated since 2026-10-27 and never sent. It was the neg-risk conversion correction to the wallet-wide pnl.net_total and pnl.realized (#29830). Its sports and esports part is inside pnl.in_scope.realized_pnl."
            },
            "correction_pending": {
              "type": "boolean",
              "description": "true while 0xinsider is still checking some of the wallet's converted neg-risk markets with a sports or esports event (not yet measured, measured and not yet checked for transfers, or its latest reads keep failing), so the correction's part inside pnl.in_scope.realized_pnl may change, or arrive where none is published yet. Omitted otherwise."
            },
            "realized": {
              "type": "number",
              "deprecated": true,
              "x-never-sent": true,
              "description": "Deprecated since 2026-10-27 and never sent. It was native Polymarket realized P&L over every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29830). Read pnl.in_scope.realized_pnl."
            },
            "unrealized": {
              "type": "number",
              "description": "Unrealized P&L in USD of the wallet's open positions on its synced markets, from the open-position aggregate (dated by the positions data_quality group). Since 2026-10-27 (#29366) a wallet that holds a sports or esports market has only sports and esports markets synced, so this covers those positions; before, it covered every Polymarket market. A wallet with no sports or esports market can still carry older markets of other categories until they are deleted."
            },
            "exact": {
              "$ref": "#/$defs/TraderPnlExact",
              "deprecated": true,
              "x-never-sent": true,
              "description": "Deprecated since 2026-10-27 and never sent: its one member was the lossless counterpart of the retired pnl.realized (#29830)."
            },
            "in_scope": {
              "$ref": "#/$defs/TraderPnlInScope",
              "description": "Additive (#27311): the wallet's sports and esports record, the figure the 0xinsider profile headlines, dated by the sports_record data_quality group. Omitted until 0xinsider has computed the wallet's record; absent means not computed yet, never zero. Also omitted for a wallet that traded no sports or esports market, which never gets a record: then stats.markets_traded is 0 and the sports_record group is partial with owner traders.last_synced (since 2026-10-29, #30589, #30657). Also omitted for a wallet that trades only combos and holds no single sports or esports market: the record counts single markets, so it has none, stats.markets_traded and stats.win_rate are omitted, and the sports_record group is partial with owner traders.last_synced (since 2026-10-29, #30637). Since 2026-10-27 it is the wallet's only P&L figure besides pnl.unrealized (#29830)."
            }
          }
        },
        "stats": {
          "type": "object",
          "description": "Sports and esports markets only since 2026-10-27 (#29830): markets_traded and win_rate come from the wallet's sports and esports record (pnl.in_scope), and total_volume from its stored trade days. A wallet that traded no sports or esports market never gets a record: markets_traded is 0 and win_rate is omitted (since 2026-10-29, #30589, #30657). A wallet that trades only combos has no record either: both are omitted (since 2026-10-29, #30637).",
          "properties": {
            "markets_traded": {
              "type": "integer",
              "description": "Sports and esports markets the wallet traded, any status: pnl.in_scope.markets, dated by the sports_record data_quality group. Omitted until the record is computed. 0 for a wallet that traded no sports or esports market, which never gets a record: at its last completed sync Polymarket counted no market for it, or the sync read its Polymarket positions and found no sports or esports market; none is stored, and no Polymarket sports or esports board lists it; the sports_record group then carries the sync clock (since 2026-10-29, #30589; the second case since #30657). Omitted for a wallet that trades only combos and holds no single sports or esports market, which has no record (since 2026-10-29, #30637). Counted every Polymarket market before 2026-10-27."
            },
            "win_rate": {
              "type": "number",
              "description": "Won over decided sports and esports markets, 0 to 1: pnl.in_scope.win_rate truncated to four places, dated by the sports_record data_quality group. Omitted until the record is computed, while the wallet has no decided sports or esports market, for a wallet that traded no sports or esports market (#30589, #30657), and for one that trades only combos (#30637). Counted every Polymarket market before 2026-10-27."
            },
            "daily_win_rate": {
              "type": "number",
              "deprecated": true,
              "x-never-sent": true,
              "description": "Deprecated since 2026-10-27 and never sent. It counted mark-to-market days over every Polymarket market of the wallet (#29830). Read stats.all.win_days and stats.all.loss_days from GET /api/v1/trader/{address}/pnl, which count sports and esports days."
            },
            "total_volume": {
              "type": "number",
              "description": "Sports and esports USD volume, all time: the sum of every stored trade day's in-scope volume (trader_trade_daily_rollups.in_scope_volume_total), the profile's Volume traded. Dated by the volume data_quality group, which carries the trader sync clock. 0 for a synced wallet with no stored trade day. Omitted before the wallet's first completed sync and while any stored day's in-scope volume is not computed yet, so a partial sum is never served. Polymarket's full-history wallet-wide volume before 2026-10-27 (#29830)."
            },
            "exact": {
              "$ref": "#/$defs/TraderStatsExact",
              "description": "Additive lossless counterpart to `total_volume`, present exactly when it is."
            }
          }
        },
        "strategy": {
          "type": "object",
          "required": [
            "strategy_type"
          ],
          "properties": {
            "strategy_type": {
              "type": "string",
              "description": "Observed trading style identifier. New rows use two_sided, category_focused, high_activity, diversified, mixed, or unclassified, counted over the wallet's sports and esports markets only. Historical identifiers remain readable during normal reclassification; style does not predict skill or intent."
            },
            "description": {
              "type": "string"
            },
            "confidence": {
              "type": "number"
            }
          }
        },
        "category_strengths": {
          "type": "object",
          "additionalProperties": true,
          "description": "Per-category rank context when expand=categories is requested. Values include available rank, category totals, performance and record counts; scaled_total_pnl is a legacy alias of total_pnl. Its measurement basis and update timing differ from the plain record returned by GET /api/v1/trader/{address}/categories, so the two need not agree. Use this for rank context and that route for the plain record. Sports and esports only (#28761): keys are sports and esports categories, and a category outside them is omitted, as on that route. The inner key-set is intentionally unconstrained and may contain additional compatibility fields."
        },
        "quant_metrics": {
          "type": "object",
          "deprecated": true,
          "x-never-sent": true,
          "additionalProperties": false,
          "required": [
            "smart_score",
            "copy_score",
            "sharpe_30d",
            "sharpe_7d",
            "profit_factor",
            "edge_consistency",
            "sharpe_percentile",
            "pf_percentile",
            "consistency_percentile"
          ],
          "description": "Deprecated since 2026-10-27 and never sent. These advanced risk and performance metrics covered every Polymarket market of the wallet, and wallet figures cover sports and esports markets only (#29589). expand=quant_metrics is still accepted and adds nothing. For the sports and esports record read pnl.in_scope here, and GET /api/v1/trader/{address}/pnl for its daily series. The member shape below is what the object held before; it is kept so existing type declarations still compile.",
          "properties": {
            "smart_score": {
              "type": [
                "number",
                "null"
              ],
              "description": "Trader smart score on a 0..100 display scale; higher is stronger. Null when unavailable."
            },
            "copy_score": {
              "type": [
                "number",
                "null"
              ],
              "description": "Copyability score, 0-100. Same base as smart_score minus penalties for traits that make a strategy hard to replicate: -20 if fewer than 50 markets traded, -15 if positions are highly concentrated, -15 if position sizing exceeds about 2x Kelly, -10 if the largest loss on one settled market exceeds 30% of the capital the wallet deployed across all its positions, -10 if edge is inconsistent; result clamped to 0-100. Higher means easier to follow. null when insufficient history."
            },
            "sharpe_30d": {
              "type": [
                "number",
                "null"
              ],
              "description": "Sharpe ratio over the trailing 30 days (risk-adjusted return; higher is better). Magnitude can be large for small samples. null when insufficient history."
            },
            "sharpe_7d": {
              "type": [
                "number",
                "null"
              ],
              "description": "Sharpe ratio over the trailing 7 days (risk-adjusted return; higher is better). null when insufficient history."
            },
            "profit_factor": {
              "type": [
                "number",
                "null"
              ],
              "description": "Gross profit divided by gross loss; greater than 1 is profitable. Capped at 1000 when there are effectively no losses. null when insufficient history."
            },
            "edge_consistency": {
              "type": [
                "number",
                "null"
              ],
              "description": "Share of the trader's last 30 days with realized P&L that closed positive, 0-1 (higher is more consistent). A day with no realized P&L is not one of them, so the window can span months. null below 10 such days; null never means 0."
            },
            "sharpe_percentile": {
              "type": [
                "number",
                "null"
              ],
              "description": "Cross-sectional percentile rank of the trader's Sharpe ratio versus all traders, 0-100. null when insufficient history."
            },
            "pf_percentile": {
              "type": [
                "number",
                "null"
              ],
              "description": "Cross-sectional percentile rank of profit factor versus all traders, 0-100. null when insufficient history."
            },
            "consistency_percentile": {
              "type": [
                "number",
                "null"
              ],
              "description": "Cross-sectional percentile rank of edge consistency versus all traders, 0-100. null when insufficient history."
            }
          }
        },
        "last_active": {
          "type": "string",
          "format": "date-time"
        },
        "synced_at": {
          "type": "string",
          "format": "date-time"
        },
        "sync_status": {
          "type": "string",
          "description": "synced, unknown, or pending."
        },
        "data_quality": {
          "$ref": "#/$defs/DataQuality",
          "description": "Data age and coverage for this trader body. Always present. Its six groups are sync (traders.last_synced, covering last_active, synced_at and sync_status), sports_record (trader_product_scope_records.computed_at, covering pnl.in_scope, stats.markets_traded and stats.win_rate: unavailable until the wallet's sports and esports record is computed, partial while it has no decided sports or esports market; for a wallet that traded no sports or esports market, which never gets a record, partial with owner traders.last_synced, as of the completed sync that found none, stats.markets_traded 0 and pnl.in_scope and stats.win_rate omitted, since 2026-10-29, #30589, #30657; for a wallet that trades only combos and holds no single sports or esports market, partial with owner traders.last_synced and all three omitted, since 2026-10-29, #30637), ranking (trader_rankings.computed_at, covering grade, score, streak_tier, forecast_score and forecast_evidence), leaderboard_rank (leaderboard_rank_refresh_state.completed_at, the completion time of the latest fully completed global rank refresh, covering rank), volume (traders.last_synced, covering stats.total_volume, the sum of the trade days the sync stores: unavailable before the first completed sync and while a stored day's sports and esports volume is not computed) and positions (trader_position_snapshots.last_refreshed_at with traders.last_synced as fallback, covering pnl.unrealized, the open-position aggregate). Since 2026-10-27 (#29830) there is no leaderboard_pnl group, and volume is dated by the sync clock instead of trader_usd_volume.observed_at. The positions clock is the latest successful /positions snapshot when one exists, otherwise the last completed trader sync. A rank or position value remains unknown or unavailable when its clock or value is absent. For an unknown wallet every group is unavailable. If the open-position read itself fails, positions is unavailable with a reason that says so, pnl.unrealized is absent, and the body is answered fresh (meta.cached false) and is not kept for later callers."
        },
        "trust": {
          "$ref": "#/$defs/TraderTrust",
          "description": "Field-level trust metadata. Present only when expand=trust or expand[]=trust is requested."
        },
        "category_records": {
          "type": "array",
          "items": {
            "$ref": "#/$defs/CategorySkillV2"
          },
          "description": "Current evidence for observed and known categories (expand=categories or expand[]=categories). Omitted unless expanded. Includes insufficient, stale, unknown and degraded rows; absence of a category is not proof of skill. The global grade is unchanged. Sports and esports only (#28827): a category outside them is omitted, as on GET /api/v1/trader/{address}/categories."
        },
        "category_skill_model": {
          "$ref": "#/$defs/CategorySkillModelReadiness"
        }
      }
    },
    "TraderPnlExact": {
      "type": "object",
      "deprecated": true,
      "required": [
        "realized"
      ],
      "description": "Deprecated since 2026-10-27 and never sent: pnl.exact held the lossless counterpart of the retired wallet-wide pnl.realized (#29830). The member shape below is what the object held before; it is kept so existing type declarations still compile.",
      "properties": {
        "realized": {
          "$ref": "#/$defs/ExactDecimal",
          "description": "Native Polymarket realized P&L plus credited maker and taker rebates, with fees included, from the trusted matching `trader_trading_pnl.net_realized_pnl` snapshot."
        }
      }
    },
    "TraderPnlInScope": {
      "type": "object",
      "required": [
        "basis",
        "realized_pnl",
        "markets",
        "markets_resolved",
        "win_rate",
        "markets_out_of_scope",
        "as_of"
      ],
      "description": "A wallet's sports and esports record (#27311). basis names the rule behind realized_pnl (#29370): polymarket_sports_esports_v1 is Polymarket's own realized P&L for the wallet in its sports and esports categories, plus the wallet's maker and taker rebates apportioned by its sports and esports share of its Polymarket volume (by cost while Polymarket reports no overall volume) and the in-scope part of any published neg-risk conversion correction; sports_esports_split_v1, used until both of the wallet's category figures are confirmed, is Polymarket's published wallet-wide realized P&L (with any published correction) split into the part earned on sports and esports markets, with fees, refunds and rebates apportioned by cost. Refreshed after each wallet sync and each read of Polymarket's category leaderboards; as_of dates the market counts.",
      "properties": {
        "basis": {
          "type": "string",
          "description": "The rule behind realized_pnl: polymarket_sports_esports_v1 (Polymarket's sports and esports category figures plus apportioned rebates) or sports_esports_split_v1 (the published realized figure split by cost). A new value means the rule changed; compare figures only within one basis."
        },
        "realized_pnl": {
          "type": [
            "number",
            "null"
          ],
          "description": "Sports and esports realized P&L in USD, display-safe. null when the split basis has no published realized figure to split."
        },
        "markets": {
          "type": "integer",
          "description": "Sports and esports markets the wallet has traded, any status."
        },
        "markets_resolved": {
          "type": "integer",
          "description": "Of those, the markets that have resolved."
        },
        "win_rate": {
          "type": [
            "number",
            "null"
          ],
          "description": "Share of decided sports and esports markets the wallet won, 0 to 1. null with no decided market."
        },
        "markets_out_of_scope": {
          "type": "integer",
          "description": "The wallet's markets outside sports and esports, which 0xinsider no longer lists: those it still stores, those whose rows it deleted and counted, and those of other categories first traded since 2026-10-26, which it does not store and counts as the wallet syncs (#30165)."
        },
        "as_of": {
          "type": "string",
          "format": "date-time",
          "description": "When the record behind these figures was computed."
        }
      }
    },
    "TraderStatsExact": {
      "type": "object",
      "required": [
        "total_volume"
      ],
      "description": "Lossless counterparts for trader statistics. The object is present exactly when stats.total_volume is.",
      "properties": {
        "total_volume": {
          "$ref": "#/$defs/ExactDecimal",
          "description": "stats.total_volume as an exact decimal: the sports and esports USD volume, the sum of every stored trade day's `trader_trade_daily_rollups.in_scope_volume_total` (#29830). Polymarket's full-history wallet-wide user volume before 2026-10-27."
        }
      }
    },
    "TraderTrust": {
      "type": "object",
      "description": "Field-level trust metadata returned only when GET /api/v1/trader/{address} includes expand=trust.",
      "required": [
        "total_pnl",
        "realized_pnl",
        "net_total_pnl",
        "unrealized_pnl",
        "markets_traded",
        "win_rate",
        "daily_win_rate",
        "total_volume",
        "grade",
        "score",
        "forecast_score",
        "forecast_evidence",
        "rank",
        "streak_tier",
        "strategy",
        "category_strengths",
        "quant_metrics",
        "last_active",
        "synced_at",
        "sync_status",
        "category_records",
        "category_skill_model"
      ],
      "properties": {
        "total_pnl": {
          "$ref": "#/$defs/TrustMetadata",
          "description": "Since 2026-10-27 always not_computed: pnl.total is retired and never sent (#29830). The key stays so the object keeps its shape."
        },
        "realized_pnl": {
          "$ref": "#/$defs/TrustMetadata",
          "description": "Since 2026-10-27 always not_computed: pnl.realized and pnl.exact are retired and never sent (#29830). The key stays so the object keeps its shape."
        },
        "net_total_pnl": {
          "$ref": "#/$defs/TrustMetadata",
          "description": "Since 2026-10-27 always not_computed: pnl.net_total is retired and never sent (#29830). The key stays so the object keeps its shape."
        },
        "pnl_correction": {
          "$ref": "#/$defs/TrustMetadata",
          "deprecated": true,
          "x-never-sent": true,
          "description": "Deprecated since 2026-10-27 and never sent: it was present only with pnl.correction, which is retired (#29830)."
        },
        "unrealized_pnl": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "markets_traded": {
          "$ref": "#/$defs/TrustMetadata",
          "description": "Computed, owned by trader_product_scope_records (markets) and dated by the record's computed_at, since 2026-10-27 (#29830). For a wallet that traded no sports or esports market, which never gets a record, owned by traders (last_synced), the completed sync that found none, and dated by it, since 2026-10-29 (#30589, #30657; owned by traders (markets_traded) until #30657)."
        },
        "win_rate": {
          "$ref": "#/$defs/TrustMetadata",
          "description": "Computed, owned by trader_product_scope_records (win_rate) and dated by the record's computed_at, since 2026-10-27 (#29830)."
        },
        "daily_win_rate": {
          "$ref": "#/$defs/TrustMetadata",
          "description": "Since 2026-10-27 always not_computed: stats.daily_win_rate is retired and never sent (#29830). The key stays so the object keeps its shape."
        },
        "total_volume": {
          "$ref": "#/$defs/TrustMetadata",
          "description": "Computed, owned by trader_trade_daily_rollups (in_scope_volume_total) and dated by traders.last_synced, since 2026-10-27 (#29830)."
        },
        "grade": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "score": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "forecast_score": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "forecast_evidence": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "rank": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "streak_tier": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "strategy": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "category_strengths": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "quant_metrics": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "last_active": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "synced_at": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "sync_status": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "category_records": {
          "$ref": "#/$defs/TrustMetadata"
        },
        "category_skill_model": {
          "$ref": "#/$defs/TrustMetadata"
        }
      }
    },
    "TrustCompleteness": {
      "type": "object",
      "description": "Whether the described value or result set is complete for its stated contract.",
      "required": [
        "status"
      ],
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "complete",
            "partial",
            "not_computed",
            "not_applicable",
            "unavailable"
          ]
        },
        "detail": {
          "type": "string"
        }
      }
    },
    "TrustFreshness": {
      "type": "object",
      "description": "Freshness metadata for a trust-critical value. This is separate from transport cache fields in ResponseMeta.",
      "required": [
        "status"
      ],
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "fresh",
            "refreshing",
            "stale",
            "not_live",
            "unknown",
            "unavailable"
          ]
        },
        "as_of": {
          "type": "string",
          "format": "date-time"
        },
        "max_age_s": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "TrustMetadata": {
      "type": "object",
      "description": "Shared source/freshness/reconciliation/completeness metadata for public API values that may be cached, stale, partial, computed, or provider-unavailable. Unavailable provider values must be represented with explicit metadata instead of fabricated zeros or empty arrays.",
      "required": [
        "source",
        "freshness",
        "reconciliation",
        "completeness"
      ],
      "properties": {
        "source": {
          "$ref": "#/$defs/TrustSource"
        },
        "freshness": {
          "$ref": "#/$defs/TrustFreshness"
        },
        "reconciliation": {
          "$ref": "#/$defs/TrustReconciliation"
        },
        "completeness": {
          "$ref": "#/$defs/TrustCompleteness"
        }
      }
    },
    "TrustReconciliation": {
      "type": "object",
      "description": "How provider-owned facts were reconciled with stored/read-model values.",
      "required": [
        "status"
      ],
      "properties": {
        "status": {
          "type": "string",
          "enum": [
            "provider_backed",
            "db_mirror",
            "computed",
            "partial",
            "not_applicable",
            "unavailable"
          ]
        },
        "detail": {
          "type": "string"
        }
      }
    },
    "TrustSource": {
      "type": "object",
      "description": "Source metadata for a trust-critical value. Providers and DB/read models own business truth; clients should not infer missing provider facts from titles, slugs, zeros, or empty arrays.",
      "required": [
        "kind",
        "owner"
      ],
      "properties": {
        "kind": {
          "type": "string",
          "enum": [
            "provider",
            "database",
            "cache",
            "computed",
            "client_input",
            "unavailable"
          ]
        },
        "owner": {
          "type": "string",
          "description": "Provider, table/read-model, cache, or service that owns the value."
        },
        "field": {
          "type": "string",
          "description": "Provider field, DB column, or computed field name when applicable."
        }
      }
    }
  }
}