openapi: 3.0.0
info:
  title: Market Data Service API
  description: |
    Real-time market data API providing ticker information, candlestick data, and order book depth for spot trading markets.
    
    ## Response Format
    All endpoints return a standard response envelope:
    
    **Success Response (HTTP 200):**
    ```json
    {
      "code": 200,
      "message": "Success message",
      "data": { /* endpoint-specific data */ }
    }
    ```
    
    **Error Response (HTTP 400, 404, 500):**
    ```json
    {
      "code": 400,
      "message": "Error message",
      "error": "Detailed error information"
    }
    ```
    
    ## Time Formats
    - Timestamps in responses are in **milliseconds** (Unix epoch * 1000)
    - Query parameters like `start_time` and `end_time` accept **milliseconds**
  version: 1.0.0
  contact:
    name: API Support
  license:
    name: Proprietary

servers:
  - url: https://api.poolthewool.com
    description: Production API Gateway

tags:
  - name: Ticker
    description: Market ticker endpoints for 24h price summary
  - name: Price
    description: Current price information
  - name: Kline
    description: Candlestick chart data
  - name: Depth
    description: Order book depth information

paths:
  /api/spot/market/ticker:
    get:
      tags:
        - Ticker
      summary: Get market ticker(s)
      description: Retrieve 24-hour ticker information for specified markets
      operationId: getTicker
      parameters:
        - name: markets
          in: query
          description: Comma-separated list of market symbols (e.g., "BTCUSDT" or "BTCUSDT,ETHUSDT"). Maximum 10 markets per request.
          required: true
          schema:
            type: string
            example: "BTCUSDT,ETHUSDT"
      responses:
        '200':
          description: Successfully retrieved ticker data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TickerResponse'
              examples:
                single:
                  value:
                    code: 200
                    message: Market ticker retrieved successfully
                    data:
                      tickers:
                        - market: "BTCUSDT"
                          last: "65000.00"
                          open: "64000.00"
                          close: "65000.00"
                          high: "66000.00"
                          low: "63000.00"
                          volume: "1500.50"
                          value: "97532500.00"
                          volume_buy: "0"
                          volume_sell: "0"
                          period: 86400
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingMarkets:
                  value:
                    code: 400
                    message: Validation error
                    error: markets query parameter is required
                tooMany:
                  value:
                    code: 400
                    message: Validation error
                    error: too many markets requested (max 10)
        '404':
          description: Market ticker not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/spot/market/ticker/all:
    get:
      tags:
        - Ticker
      summary: Get all market tickers
      description: Retrieve 24-hour ticker information for all available markets
      operationId: getAllTickers
      responses:
        '200':
          description: Successfully retrieved all ticker data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TickerResponse'
              examples:
                allMarkets:
                  value:
                    code: 200
                    message: All market tickers retrieved successfully
                    data:
                      tickers:
                        - market: "BTCUSDT"
                          last: "65000.00"
                          open: "64000.00"
                          close: "65000.00"
                          high: "66000.00"
                          low: "63000.00"
                          volume: "1500.50"
                          value: "97532500.00"
                          volume_buy: "0"
                          volume_sell: "0"
                          period: 86400
                        - market: "ETHUSDT"
                          last: "3500.00"
                          open: "3400.00"
                          close: "3500.00"
                          high: "3600.00"
                          low: "3300.00"
                          volume: "50000.00"
                          value: "175000000.00"
                          volume_buy: "0"
                          volume_sell: "0"
                          period: 86400
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/spot/market/price:
    get:
      tags:
        - Price
      summary: Get current market price
      description: Retrieve the latest price for a specific market
      operationId: getPrice
      parameters:
        - name: market
          in: query
          description: Market symbol (e.g., "BTCUSDT")
          required: true
          schema:
            type: string
            example: "BTCUSDT"
      responses:
        '200':
          description: Successfully retrieved market price
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PriceResponse'
              examples:
                success:
                  value:
                    code: 200
                    message: Market price retrieved successfully
                    data:
                      price:
                        market: "BTCUSDT"
                        last: "65000.00"
                        updated_at: 1717231200000
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingMarket:
                  value:
                    code: 400
                    message: Validation error
                    error: market query parameter is required
        '404':
          description: Market price not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/spot/market/kline:
    get:
      tags:
        - Kline
      summary: Get candlestick data
      description: |
        Retrieve candlestick (OHLCV) data for a market at specified interval.
        
        When `end_time` is not provided, the response includes the latest in-progress candle.
      operationId: getKline
      parameters:
        - name: market
          in: query
          description: Market symbol (e.g., "BTCUSDT")
          required: true
          schema:
            type: string
            example: "BTCUSDT"
        - name: period
          in: query
          description: |
            Candlestick interval. Supported values:
            - `1min`, `5min`, `15min`, `30min`
            - `1hour`, `4hour`, `6hour`, `8hour`, `12hour`
            - `1day`, `3day`, `1week`, `1month`
          required: true
          schema:
            type: string
            enum:
              - 1min
              - 5min
              - 15min
              - 30min
              - 1hour
              - 4hour
              - 6hour
              - 8hour
              - 12hour
              - 1day
              - 3day
              - 1week
              - 1month
            example: "1day"
        - name: limit
          in: query
          description: Number of candles to return (default 100, max 1000)
          required: false
          schema:
            type: integer
            minimum: 1
            maximum: 1000
            default: 100
            example: 100
        - name: start_time
          in: query
          description: Start time in milliseconds (Unix epoch * 1000). If omitted, returns most recent candles.
          required: false
          schema:
            type: integer
            format: int64
            example: 1717227600000
        - name: end_time
          in: query
          description: |
            End time in milliseconds (Unix epoch * 1000). If omitted, includes the latest in-progress candle.
          required: false
          schema:
            type: integer
            format: int64
            example: 1717314000000
      responses:
        '200':
          description: Successfully retrieved candlestick data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/KlineResponse'
              examples:
                success:
                  value:
                    code: 200
                    message: Market klines retrieved successfully
                    data:
                      klines:
                        - market: "BTCUSDT"
                          created_at: 1717227600000
                          open: "64500.00"
                          close: "65000.00"
                          high: "65200.00"
                          low: "64400.00"
                          volume: "120.5"
                          value: "7808400.00"
                        - market: "BTCUSDT"
                          created_at: 1717314000000
                          open: "65000.00"
                          close: "65500.00"
                          high: "65800.00"
                          low: "64800.00"
                          volume: "135.2"
                          value: "8869200.00"
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingMarket:
                  value:
                    code: 400
                    message: Validation error
                    error: market query parameter is required
                missingPeriod:
                  value:
                    code: 400
                    message: Validation error
                    error: period query parameter is required
                invalidPeriod:
                  value:
                    code: 400
                    message: Validation error
                    error: invalid period format
                invalidLimit:
                  value:
                    code: 400
                    message: Validation error
                    error: limit must be a positive integer
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

  /api/spot/market/depth:
    get:
      tags:
        - Depth
      summary: Get order book depth
      description: |
        Retrieve order book depth (asks and bids) for a market.
        
        Supports price level aggregation via the `interval` parameter for performance optimization.
      operationId: getDepth
      parameters:
        - name: market
          in: query
          description: Market symbol (e.g., "BTCUSDT")
          required: true
          schema:
            type: string
            example: "BTCUSDT"
        - name: limit
          in: query
          description: Number of price levels on each side (asks/bids)
          required: false
          schema:
            type: integer
            enum:
              - 5
              - 10
              - 20
              - 50
            default: 10
            example: 10
        - name: interval
          in: query
          description: |
            Price level merge step for aggregation. 
            Use `"0"` for no aggregation (default), or a decimal price step for coarser granularity.
          required: false
          schema:
            type: string
            default: "0"
            example: "0"
      responses:
        '200':
          description: Successfully retrieved order book depth
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DepthResponse'
              examples:
                success:
                  value:
                    code: 200
                    message: Market depth retrieved successfully
                    data:
                      market: "BTCUSDT"
                      is_full: true
                      depth:
                        asks:
                          - ["65001.00", "1.5"]
                          - ["65002.00", "2.0"]
                          - ["65003.00", "1.2"]
                        bids:
                          - ["64999.00", "1.0"]
                          - ["64998.00", "1.5"]
                          - ["64997.00", "0.8"]
                        checksum: 123456789
                        last: "65000.00"
                        updated_at: 1717231200000
        '400':
          description: Invalid request parameters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
              examples:
                missingMarket:
                  value:
                    code: 400
                    message: Validation error
                    error: market query parameter is required
                invalidLimit:
                  value:
                    code: 400
                    message: Validation error
                    error: invalid depth limit
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'

components:
  schemas:
    # ===== Common Schemas =====
    SuccessResponse:
      type: object
      required:
        - code
        - message
        - data
      properties:
        code:
          type: integer
          example: 200
          description: HTTP status code
        message:
          type: string
          example: Success
          description: Human-readable success message
        data:
          type: object
          description: Response payload (schema varies by endpoint)

    ErrorResponse:
      type: object
      required:
        - code
        - message
      properties:
        code:
          type: integer
          example: 400
          description: HTTP status code
        message:
          type: string
          example: Validation error
          description: Error category
        error:
          type: string
          example: markets query parameter is required
          description: Detailed error message

    # ===== Ticker Schemas =====
    TickerDTO:
      type: object
      required:
        - market
        - last
        - open
        - close
        - high
        - low
        - volume
        - value
        - volume_buy
        - volume_sell
        - period
      properties:
        market:
          type: string
          description: Market symbol
          example: "BTCUSDT"
        last:
          type: string
          description: Last traded price (24h close)
          example: "65000.00"
        open:
          type: string
          description: Opening price (24h open)
          example: "64000.00"
        close:
          type: string
          description: Closing price (same as last)
          example: "65000.00"
        high:
          type: string
          description: Highest price in 24h
          example: "66000.00"
        low:
          type: string
          description: Lowest price in 24h
          example: "63000.00"
        volume:
          type: string
          description: 24h trading volume in base asset
          example: "1500.50"
        value:
          type: string
          description: 24h trading volume in quote asset
          example: "97532500.00"
        volume_buy:
          type: string
          description: Reserved field (always "0")
          example: "0"
        volume_sell:
          type: string
          description: Reserved field (always "0")
          example: "0"
        period:
          type: integer
          description: Period in seconds (always 86400 for 24h)
          example: 86400

    TickersData:
      type: object
      required:
        - tickers
      properties:
        tickers:
          type: array
          items:
            $ref: '#/components/schemas/TickerDTO'

    TickerResponse:
      allOf:
        - $ref: '#/components/schemas/SuccessResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/TickersData'

    # ===== Price Schemas =====
    PriceDTO:
      type: object
      required:
        - market
        - last
        - updated_at
      properties:
        market:
          type: string
          description: Market symbol
          example: "BTCUSDT"
        last:
          type: string
          description: Current price
          example: "65000.00"
        updated_at:
          type: integer
          format: int64
          description: Timestamp in milliseconds
          example: 1717231200000

    PriceData:
      type: object
      required:
        - price
      properties:
        price:
          $ref: '#/components/schemas/PriceDTO'

    PriceResponse:
      allOf:
        - $ref: '#/components/schemas/SuccessResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/PriceData'

    # ===== Kline Schemas =====
    KlineDTO:
      type: object
      required:
        - market
        - created_at
        - open
        - close
        - high
        - low
        - volume
        - value
      properties:
        market:
          type: string
          description: Market symbol
          example: "BTCUSDT"
        created_at:
          type: integer
          format: int64
          description: Candle open time in milliseconds
          example: 1717227600000
        open:
          type: string
          description: Opening price of candle
          example: "64500.00"
        close:
          type: string
          description: Closing price of candle
          example: "65000.00"
        high:
          type: string
          description: Highest price in candle
          example: "65200.00"
        low:
          type: string
          description: Lowest price in candle
          example: "64400.00"
        volume:
          type: string
          description: Trading volume in base asset
          example: "120.5"
        value:
          type: string
          description: Trading volume in quote asset
          example: "7808400.00"

    KlinesData:
      type: object
      required:
        - klines
      properties:
        klines:
          type: array
          items:
            $ref: '#/components/schemas/KlineDTO'

    KlineResponse:
      allOf:
        - $ref: '#/components/schemas/SuccessResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/KlinesData'

    # ===== Depth Schemas =====
    OrderLevel:
      type: array
      minItems: 2
      maxItems: 2
      items:
        type: string
      description: "Price level: [price, quantity]"
      example: ["65001.00", "1.5"]

    DepthInfo:
      type: object
      required:
        - asks
        - bids
        - checksum
        - last
        - updated_at
      properties:
        asks:
          type: array
          description: Sell orders sorted by price (lowest first)
          items:
            $ref: '#/components/schemas/OrderLevel'
        bids:
          type: array
          description: Buy orders sorted by price (highest first)
          items:
            $ref: '#/components/schemas/OrderLevel'
        checksum:
          type: integer
          format: uint32
          description: Checksum of order book state
          example: 123456789
        last:
          type: string
          description: Last traded price
          example: "65000.00"
        updated_at:
          type: integer
          format: int64
          description: Timestamp in milliseconds
          example: 1717231200000

    DepthDTO:
      type: object
      required:
        - market
        - is_full
        - depth
      properties:
        market:
          type: string
          description: Market symbol
          example: "BTCUSDT"
        is_full:
          type: boolean
          description: Whether the snapshot is a full order book
          example: true
        depth:
          $ref: '#/components/schemas/DepthInfo'

    DepthResponse:
      allOf:
        - $ref: '#/components/schemas/SuccessResponse'
        - type: object
          properties:
            data:
              $ref: '#/components/schemas/DepthDTO'

    # ===== Error Schemas =====
    ValidationError:
      allOf:
        - $ref: '#/components/schemas/ErrorResponse'
        - type: object
          properties:
            code:
              example: 400
            message:
              example: Validation error

    NotFoundError:
      allOf:
        - $ref: '#/components/schemas/ErrorResponse'
        - type: object
          properties:
            code:
              example: 404
            message:
              example: Not found

    InternalError:
      allOf:
        - $ref: '#/components/schemas/ErrorResponse'
        - type: object
          properties:
            code:
              example: 500
            message:
              example: Internal server error
