> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kairos.trade/llms.txt
> Use this file to discover all available pages before exploring further.

# Get a trader's open/closed positions and derived performance stats

> Returns a trader's positions plus performance metrics computed from a full-inventory scan — served independently of the unified profile so the Positions tab and stats panel can load on their own fetch. Positions are filtered by `status` (open/closed/all), sorted by current value (largest first), and paginated via `limit`/`offset`; `has_more` indicates another page exists in the filtered set. Market names/icons are resolved only for the returned page, so wallets holding a very large number of positions don't blow past internal query limits. `performance` (win rate, total PnL, volume, positions_value, etc.) is always computed over the wallet's FULL inventory, not just the returned page. `include_redeemable` additionally includes resolved positions still awaiting on-chain redemption. **Public endpoint — no authentication required** (trader data is public). Rate-limited per client IP at 30 requests/minute. Responses are cacheable at the edge.




## OpenAPI

````yaml /openapi/data-api.yaml get /trader-stats/positions/{wallet_address}
openapi: 3.1.0
info:
  title: Kairos Data API
  version: 1.0.0
  summary: >-
    The full Kairos data plane — markets, candles, trades, search, discover,
    sports, trader analytics, and PnL.
  description: |
    The Kairos Data API at `data.kairos.trade` is the platform's primary data
    plane: market metadata and prices, OHLCV candles, live venue trade proxies,
    normalized trade history, full-text search, discovery feeds, the sports
    catalog, public trader analytics, and account PnL.

    ## Authentication

    Most endpoints accept a Kairos **API key** (`X-Client-Id` + `X-Api-Key` +
    `X-Api-Secret`, all three) or a first-party session JWT. Endpoints tagged
    `public` (trader analytics, provider configs, several sports feeds) need
    no credentials at all. Some endpoints additionally require an API-key
    **scope** (`trade:read`, `position:read`) — stated per operation.

    For high-volume market-data consumption (candles/trades/metadata at
    scale), prefer the dedicated **Market Data API** at `md.kairos.trade` —
    it has higher budgets, ETag caching, and a binary candle format.

    ## Rate limits

    Rate limits use a sliding window keyed on the authenticated user (JWT
    `sub`) or, for anonymous callers, the trusted client IP. Routes belong to
    a named **bucket** (`x-kairos-bucket`) whose per-minute budget is shared
    by every route in it; routes with no bucket run under the service default
    of 100/minute. `x-kairos-rate-limit` states the bucket's compile-time
    default — operators can raise or lower a bucket at runtime, so treat the
    documented number as the baseline, not a contract. 429 responses carry
    `Retry-After` and `X-RateLimit-*`.

    ## Conventions

    - Prices are on the **0–100 cents scale** unless a field says otherwise
      (trader-analytics position/trade prices use the 0–1 scale; each field's
      description states its scale).
    - Errors: `{"detail": "<message>"}` for handler errors; FastAPI's
      standard validation envelope for 422s. Errors surfaced from a venue
      adapter instead use `{"error", "provider", "operation", "message"}` —
      see `DataProviderError`. Unhandled failures always return the generic
      500 body; internal details are logged, never returned.
    - Every request body is capped at 8 MiB service-wide (413).
  contact:
    name: Kairos
    url: https://app.kairos.trade/docs/api-reference
  termsOfService: https://kairos.trade/terms
servers:
  - url: https://data.kairos.trade
    description: Production
  - url: https://staging-data.kairos.trade
    description: Staging
security:
  - apiKeyClientId: []
    apiKeyKey: []
    apiKeySecret: []
paths:
  /trader-stats/positions/{wallet_address}:
    get:
      tags:
        - Trader Analytics
      summary: Get a trader's open/closed positions and derived performance stats
      description: >
        Returns a trader's positions plus performance metrics computed from a
        full-inventory scan — served independently of the unified profile so the
        Positions tab and stats panel can load on their own fetch. Positions are
        filtered by `status` (open/closed/all), sorted by current value (largest
        first), and paginated via `limit`/`offset`; `has_more` indicates another
        page exists in the filtered set. Market names/icons are resolved only
        for the returned page, so wallets holding a very large number of
        positions don't blow past internal query limits. `performance` (win
        rate, total PnL, volume, positions_value, etc.) is always computed over
        the wallet's FULL inventory, not just the returned page.
        `include_redeemable` additionally includes resolved positions still
        awaiting on-chain redemption. **Public endpoint — no authentication
        required** (trader data is public). Rate-limited per client IP at 30
        requests/minute. Responses are cacheable at the edge.
      operationId: getTraderPositions
      parameters:
        - name: wallet_address
          in: path
          required: true
          schema:
            type: string
          description: Ethereum or Solana wallet address (validated/normalized as above).
          example: '0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b'
        - name: include_redeemable
          in: query
          required: false
          schema:
            type: boolean
            default: false
          description: Include resolved positions still waiting for redemption.
        - name: provider
          in: query
          required: false
          schema:
            type: string
          description: >-
            Provider override (polymarket, kalshi, opinion, predictfun).
            Auto-detected if omitted.
          example: polymarket
        - name: limit
          in: query
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 200
          description: Max positions to return per page (sorted by value, largest first).
        - name: offset
          in: query
          required: false
          schema:
            type: integer
            minimum: 0
            default: 0
          description: Number of positions to skip (pagination).
        - name: status
          in: query
          required: false
          schema:
            type: string
            enum:
              - all
              - open
              - closed
            default: all
          description: Filter the returned page by position status.
      responses:
        '200':
          description: Positions page plus full-inventory performance stats.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TraderPositionsResponse'
        '400':
          description: Malformed wallet address or unrecognized provider.
        '422':
          $ref: '#/components/responses/DataValidationError'
        '429':
          $ref: '#/components/responses/DataRateLimited'
        '500':
          description: Unexpected error fetching trader positions.
      security: []
components:
  schemas:
    TraderPositionsResponse:
      type: object
      description: >
        A page of a wallet's positions plus performance stats derived from the
        full inventory in the same scan.
      required:
        - wallet_address
        - performance
        - open_positions
        - closed_positions
      properties:
        wallet_address:
          type: string
          example: '0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b'
        performance:
          $ref: '#/components/schemas/TraderPerformance'
        open_positions:
          type: array
          items:
            $ref: '#/components/schemas/TraderPosition'
        closed_positions:
          type: array
          items:
            $ref: '#/components/schemas/TraderPosition'
        has_more:
          type: boolean
          default: false
          description: >-
            True when more positions exist beyond this page (open+closed
            combined, sorted by value).
    TraderPerformance:
      type: object
      description: >-
        Aggregated trader performance metrics, always computed over the full
        inventory (not a paginated page).
      required:
        - wallet_address
        - total_realized_pnl
        - total_unrealized_pnl
        - total_pnl
        - open_positions
        - closed_positions
        - total_positions
        - winning_positions
        - losing_positions
        - win_rate
        - total_volume
        - markets_traded
        - last_updated
      properties:
        wallet_address:
          type: string
          example: '0x1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b'
        total_realized_pnl:
          type: string
          format: decimal
          example: '1250.4382'
        total_unrealized_pnl:
          type: string
          format: decimal
          example: '300.00'
        total_pnl:
          type: string
          format: decimal
          example: '1550.4382'
        roi_percent:
          type: string
          format: decimal
          default: '0'
          example: '12.75'
        open_positions:
          type: integer
          minimum: 0
          example: 4
        closed_positions:
          type: integer
          minimum: 0
          example: 27
        total_positions:
          type: integer
          minimum: 0
          example: 31
        positions_value:
          type: string
          format: decimal
          default: '0'
          description: >-
            Cost basis (deployed capital) of OPEN positions, summed over the
            full inventory.
          example: '420.00'
        winning_positions:
          type: integer
          minimum: 0
          example: 18
        losing_positions:
          type: integer
          minimum: 0
          example: 9
        win_rate:
          type: number
          format: double
          minimum: 0
          maximum: 1
          description: Win rate over closed, resolved positions.
          example: 0.6667
        total_volume:
          type: string
          format: decimal
          minimum: '0'
          example: '18420.55'
        markets_traded:
          type: integer
          minimum: 0
          example: 12
        join_date:
          type: string
          format: date-time
          nullable: true
          description: Polymarket account join date, when known.
        profile_views:
          type: integer
          default: 0
          example: 340
        largest_win:
          type: string
          format: decimal
          nullable: true
          example: '512.30'
        last_updated:
          type: string
          format: date-time
          example: '2026-07-22T14:03:11Z'
    TraderPosition:
      type: object
      description: A single current or historical position held by a trader.
      required:
        - market_id
        - token_id
        - outcome
        - size
        - entry_price
        - cost_basis
        - realized_pnl
        - status
        - provider
      properties:
        market_id:
          type: string
          example: 0xabc123condition
        market_name:
          type: string
          nullable: true
          example: Will the Fed cut rates in September?
        icon:
          type: string
          nullable: true
          description: Market icon/image URL.
          example: https://cdn.kairos.trade/markets/abc123.png
        token_id:
          type: string
          example: 10723948572...4
        outcome:
          type: string
          description: Outcome label — YES/NO or a token symbol.
          example: 'YES'
        size:
          type: string
          format: decimal
          description: Position size (>= 0).
          example: '150.0'
        entry_price:
          type: string
          format: decimal
          description: Average entry price (>= 0), 0-1 scale.
          example: '0.42'
        current_price:
          type: string
          format: decimal
          nullable: true
          description: Current mark price (>= 0), 0-1 scale.
          example: '0.55'
        cost_basis:
          type: string
          format: decimal
          description: Total USD cost basis for this position (>= 0).
          example: '63.00'
        unrealized_pnl:
          type: string
          format: decimal
          nullable: true
          example: '19.50'
        realized_pnl:
          type: string
          format: decimal
          description: Realized PnL booked against this position so far.
          example: '0.00'
        status:
          type: string
          enum:
            - OPEN
            - CLOSED
        opened_at:
          type: string
          format: date-time
          nullable: true
        closed_at:
          type: string
          format: date-time
          nullable: true
        provider:
          type: string
          description: Venue the position was traded on.
          default: polymarket
          example: polymarket
  responses:
    DataValidationError:
      description: Request failed FastAPI parameter validation.
      content:
        application/json:
          schema:
            type: object
            required:
              - detail
            properties:
              detail:
                type: array
                description: >-
                  One entry per failed field, with location, message, and error
                  type.
                items:
                  type: object
                  additionalProperties: true
    DataRateLimited:
      description: >
        Rate limit exceeded for this route's sliding window, keyed on the
        session `sub` when

        authenticated and on the trusted client IP otherwise. Honor
        `Retry-After`. A per-API-key

        data ceiling (set per credential) rejects with `{"detail": "API key data
        rate limit

        exceeded"}` instead of the `error` envelope below.
      headers:
        Retry-After:
          schema:
            type: integer
        X-RateLimit-Limit:
          schema:
            type: integer
        X-RateLimit-Remaining:
          schema:
            type: integer
        X-RateLimit-Reset:
          schema:
            type: integer
      content:
        application/json:
          schema:
            type: object
            properties:
              error:
                type: string
                example: 'Rate limit exceeded: 100 per 1 minute'
  securitySchemes:
    apiKeyClientId:
      type: apiKey
      in: header
      name: X-Client-Id
      description: >-
        Credential client id (`kairos_ck_...`). Must be sent together with
        X-Api-Key and X-Api-Secret.
    apiKeyKey:
      type: apiKey
      in: header
      name: X-Api-Key
      description: 64-char hex API key.
    apiKeySecret:
      type: apiKey
      in: header
      name: X-Api-Secret
      description: 64-char hex API secret.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.