{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/0xinsider-com/json-schema/0xinsider-com-trader-pnl-schema.json",
  "title": "TraderPnl",
  "description": "A trader's sports and esports daily P&L object. `id`, `freshness_at`, `series_status` and `realized` are always present. The five sections -- `entries`, `stats`, `monthly`, `year_totals`, `drawdown` -- are present unless the request's `sections` parameter excluded them, so a request that sends no `sections` always carries all five. An excluded section is absent from the object, never null and never an empty array. While `series_status` is `pending` the sections are empty and never mean zero.",
  "x-generated": "2026-10-31",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/0xinsider-com-openapi.json#/components/schemas/TraderPnl",
  "type": "object",
  "required": [
    "id",
    "freshness_at",
    "series_status",
    "realized"
  ],
  "properties": {
    "id": {
      "type": "string",
      "description": "Prefixed trader ID (`trd_...`)."
    },
    "view": {
      "type": "object",
      "description": "Representation parameters applied to this body. Present only when the request sent `from`, `to` or `sections`; omitted otherwise, which is what keeps a no-parameter response identical to the one this route served before the parameters existed.",
      "required": [
        "from",
        "to",
        "sections",
        "entries_total",
        "entries_in_window",
        "anchor"
      ],
      "additionalProperties": false,
      "properties": {
        "from": {
          "type": [
            "string",
            "null"
          ],
          "format": "date",
          "description": "Inclusive UTC lower bound applied to the daily series; null when the request left the series unbounded below."
        },
        "to": {
          "type": [
            "string",
            "null"
          ],
          "format": "date",
          "description": "Inclusive UTC upper bound applied to the daily series; null when the request left the series unbounded above."
        },
        "sections": {
          "type": "array",
          "description": "Sections this body carries, in the order the object publishes them, whatever order the query listed.",
          "items": {
            "type": "string",
            "enum": [
              "entries",
              "stats",
              "monthly",
              "year_totals",
              "drawdown"
            ]
          }
        },
        "entries_total": {
          "type": "integer",
          "description": "Points in the full stored daily series, before the window. Compare with entries_in_window to tell a clipped chart from a wallet that really has that many days."
        },
        "entries_in_window": {
          "type": "integer",
          "description": "Points of the daily series inside the window. Equal to entries_total when no bound narrowed it, and reported whether or not entries was among the requested sections."
        },
        "anchor": {
          "type": [
            "object",
            "null"
          ],
          "description": "The last daily point strictly before `from`: the cumulative baseline the window was cut away from. null when the request set no lower bound, or when the window starts at or before the first stored point and the slice already begins at the start of the history. Cumulative values in `entries` and `drawdown` are never rebased to the window, so this is the figure to subtract for a window-relative change.",
          "required": [
            "date",
            "cumulative_profit",
            "total_pnl",
            "drawdown"
          ],
          "additionalProperties": false,
          "properties": {
            "date": {
              "type": "string",
              "format": "date"
            },
            "cumulative_profit": {
              "type": [
                "number",
                "null"
              ],
              "description": "Cumulative profit carried into the window; null when the stored point has none, the same nullability entries[].cumulative_profit has."
            },
            "total_pnl": {
              "type": [
                "number",
                "null"
              ],
              "description": "Cumulative total P&L carried into the window; null on the same terms."
            },
            "drawdown": {
              "type": [
                "number",
                "null"
              ],
              "description": "Underwater value at the anchor date; null when that date has no drawdown point, which happens exactly when its cumulative_profit is null. The running peak behind the window is cumulative_profit minus drawdown (drawdown is zero or negative)."
            }
          }
        }
      }
    },
    "freshness_at": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time",
      "description": "RFC3339 served-freshness clock: when the wallet's sports and esports record, which this series is read from, was last computed, or, for a wallet that traded no sports or esports market (#30589, #30657) or trades only combos (#30637) and so has no record, its last completed sync; null while series_status is pending. Always present, so read it as a value that can be null rather than a key that can be missing."
    },
    "series_status": {
      "type": "string",
      "enum": [
        "ready",
        "pending"
      ],
      "description": "`ready` when the series is served; an empty one is a wallet with no sports or esports day, or one that traded no sports or esports market (#30589, #30657) or trades only combos (#30637). `pending` when the wallet's sports and esports record does not carry the daily series yet: every section is empty, realized is null, and the empty sections never mean zero. Retry later."
    },
    "realized": {
      "type": [
        "object",
        "null"
      ],
      "description": "How the daily series adds up to the wallet's Sports P&L, full precision: dated_pnl + undated_pnl = realized_pnl. null while series_status is pending, and for a wallet that traded no sports or esports market or trades only combos, which has no record (#30589, #30657, #30637).",
      "required": [
        "basis",
        "realized_pnl",
        "dated_pnl",
        "undated_pnl"
      ],
      "additionalProperties": false,
      "properties": {
        "basis": {
          "type": "string",
          "enum": [
            "polymarket_sports_esports_v1",
            "sports_esports_split_v1"
          ],
          "description": "The rule behind realized_pnl, the same basis as pnl.in_scope.basis on GET /api/v1/trader/{address}."
        },
        "realized_pnl": {
          "type": [
            "number",
            "null"
          ],
          "description": "The wallet's Sports P&L: pnl.in_scope.realized_pnl on GET /api/v1/trader/{address}. null when the wallet has no published realized figure."
        },
        "dated_pnl": {
          "type": "number",
          "description": "The sum of every day's daily_change over the full history, whatever from/to say."
        },
        "undated_pnl": {
          "type": [
            "number",
            "null"
          ],
          "description": "realized_pnl less dated_pnl. realized_pnl starts from Polymarket's figures under either basis (its sports and esports figures, or its published figure for the whole wallet split by cost) and the days from the per-market record, so undated_pnl holds the wallet's share of Polymarket rebates, the in-scope part of the neg-risk conversion correction, any market with no trade date, and the difference between Polymarket's figure and the per-market record, which on some wallets is most of it. null exactly when realized_pnl is."
        }
      }
    },
    "entries": {
      "type": "array",
      "description": "Sports and esports daily P&L series (oldest-first): one point for each UTC day with realized P&L or sports and esports volume. Present unless the request's `sections` excluded it, and clipped to `from`/`to` when either is set. cumulative_profit and total_pnl are the running sum of daily_change from the start of the history, so a clipped slice keeps the same economic meaning; view.anchor carries the point before the window.",
      "items": {
        "type": "object",
        "required": [
          "date",
          "daily_change"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "markets_traded": {
            "type": "integer",
            "description": "Sports and esports markets this wallet traded on this UTC day, counted from the fills 0xinsider stores for it. Omitted on a day whose stored fills include a market outside sports and esports (stored before October 2026), where the count would include it, and on a day above 20 times the wallet's median day."
          },
          "total_volume": {
            "type": "number",
            "description": "Volume in USD this wallet traded on this UTC day in sports and esports markets, buys and sells: each fill's size times its price, fees excluded, the measure of Polymarket user-volume `volume_usdc`, summed from the fills 0xinsider stores for it. A day stored before 2026-10-27 counts the cash each fill moved, fee included, until it is recomputed. Not Polymarket's share count, and not the full-history stats.total_volume on GET /api/v1/trader/{address}, which covers every market. Omitted on a day with realized P&L and no stored sports or esports fill, and, with markets_traded, on a day above 20 times the wallet's median day."
          },
          "cumulative_profit": {
            "type": "number",
            "description": "Running sum of daily_change through this day."
          },
          "total_pnl": {
            "type": "number",
            "description": "The same running sum as cumulative_profit."
          },
          "daily_change": {
            "type": "number",
            "description": "Realized P&L of the wallet's sports and esports markets dated to this UTC day: a settled market on its resolution day, else its last trade day; an open market's realized part on its last trade day. 0 on a day with volume and nothing realized."
          }
        }
      }
    },
    "stats": {
      "type": "object",
      "description": "Pre-derived period stats. Present unless the request's `sections` excluded it. Always the published all/90d/30d/7d windows over the full stored history; `from`/`to` never recompute them over the request's range.",
      "required": [
        "all",
        "d90",
        "d30",
        "d7"
      ],
      "properties": {
        "all": {
          "type": "object",
          "required": [
            "current",
            "change",
            "change_pct",
            "best_day",
            "worst_day",
            "win_days",
            "loss_days",
            "avg_day",
            "rebase_anchor"
          ],
          "properties": {
            "current": {
              "type": "number"
            },
            "change": {
              "type": "number"
            },
            "change_pct": {
              "type": "number"
            },
            "best_day": {
              "type": "number"
            },
            "best_day_date": {
              "type": "string",
              "format": "date"
            },
            "worst_day": {
              "type": "number"
            },
            "worst_day_date": {
              "type": "string",
              "format": "date"
            },
            "win_days": {
              "type": "integer"
            },
            "loss_days": {
              "type": "integer"
            },
            "avg_day": {
              "type": "number"
            },
            "rebase_anchor": {
              "type": "number"
            }
          }
        },
        "d90": {
          "type": "object",
          "required": [
            "current",
            "change",
            "change_pct",
            "best_day",
            "worst_day",
            "win_days",
            "loss_days",
            "avg_day",
            "rebase_anchor"
          ],
          "properties": {
            "current": {
              "type": "number"
            },
            "change": {
              "type": "number"
            },
            "change_pct": {
              "type": "number"
            },
            "best_day": {
              "type": "number"
            },
            "best_day_date": {
              "type": "string",
              "format": "date"
            },
            "worst_day": {
              "type": "number"
            },
            "worst_day_date": {
              "type": "string",
              "format": "date"
            },
            "win_days": {
              "type": "integer"
            },
            "loss_days": {
              "type": "integer"
            },
            "avg_day": {
              "type": "number"
            },
            "rebase_anchor": {
              "type": "number"
            }
          }
        },
        "d30": {
          "type": "object",
          "required": [
            "current",
            "change",
            "change_pct",
            "best_day",
            "worst_day",
            "win_days",
            "loss_days",
            "avg_day",
            "rebase_anchor"
          ],
          "properties": {
            "current": {
              "type": "number"
            },
            "change": {
              "type": "number"
            },
            "change_pct": {
              "type": "number"
            },
            "best_day": {
              "type": "number"
            },
            "best_day_date": {
              "type": "string",
              "format": "date"
            },
            "worst_day": {
              "type": "number"
            },
            "worst_day_date": {
              "type": "string",
              "format": "date"
            },
            "win_days": {
              "type": "integer"
            },
            "loss_days": {
              "type": "integer"
            },
            "avg_day": {
              "type": "number"
            },
            "rebase_anchor": {
              "type": "number"
            }
          }
        },
        "d7": {
          "type": "object",
          "required": [
            "current",
            "change",
            "change_pct",
            "best_day",
            "worst_day",
            "win_days",
            "loss_days",
            "avg_day",
            "rebase_anchor"
          ],
          "properties": {
            "current": {
              "type": "number"
            },
            "change": {
              "type": "number"
            },
            "change_pct": {
              "type": "number"
            },
            "best_day": {
              "type": "number"
            },
            "best_day_date": {
              "type": "string",
              "format": "date"
            },
            "worst_day": {
              "type": "number"
            },
            "worst_day_date": {
              "type": "string",
              "format": "date"
            },
            "win_days": {
              "type": "integer"
            },
            "loss_days": {
              "type": "integer"
            },
            "avg_day": {
              "type": "number"
            },
            "rebase_anchor": {
              "type": "number"
            }
          }
        }
      }
    },
    "monthly": {
      "type": "array",
      "description": "Per-month P&L aggregation. Present unless the request's `sections` excluded it. Whole months over the full stored history, never clipped to `from`/`to`, so a month is never a partial month.",
      "items": {
        "type": "object",
        "required": [
          "year",
          "month",
          "pnl",
          "markets_traded"
        ],
        "properties": {
          "year": {
            "type": "integer"
          },
          "month": {
            "type": "integer"
          },
          "pnl": {
            "type": "number"
          },
          "markets_traded": {
            "type": [
              "integer",
              "null"
            ],
            "description": "The month's entries[].markets_traded summed: a market traded on several days counts once a day. null when a day of the month has total_volume and no markets_traded, a day whose stored fills include a market outside sports and esports, where a sum would undercount. A day with no stored fill, or above 20 times the wallet's median day, adds 0."
          }
        }
      }
    },
    "year_totals": {
      "type": "array",
      "description": "Per-year P&L totals (ascending by year). Present unless the request's `sections` excluded it. Whole years over the full stored history, never clipped to `from`/`to`.",
      "items": {
        "type": "object",
        "required": [
          "year",
          "pnl"
        ],
        "properties": {
          "year": {
            "type": "integer"
          },
          "pnl": {
            "type": "number"
          }
        }
      }
    },
    "drawdown": {
      "type": "array",
      "description": "Underwater (drawdown) series. Present unless the request's `sections` excluded it, and clipped to `from`/`to` when either is set. The running peak behind each point is the full-history peak, so a clipped slice is not rebased; view.anchor.drawdown carries the value at the point before the window.",
      "items": {
        "type": "object",
        "required": [
          "date",
          "cumulative_profit",
          "drawdown"
        ],
        "properties": {
          "date": {
            "type": "string",
            "format": "date"
          },
          "cumulative_profit": {
            "type": "number"
          },
          "drawdown": {
            "type": "number"
          }
        }
      }
    }
  }
}