openapi: 3.0.3
info:
  title: DSTA Exchange Service
  description: Multi-exchange gateway — market data, order management, WebSocket streams, and audit log.
  version: 0.1.0
servers:
  - url: http://localhost:8005
    description: Local development
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    Ticker:
      type: object
      properties:
        symbol:
          type: string
        last:
          type: number
        bid:
          type: number
        ask:
          type: number
        volume:
          type: number
        timestamp:
          type: string
          format: date-time
    OrderBookLevel:
      type: object
      properties:
        price:
          type: number
        quantity:
          type: number
    OrderBookSnapshot:
      type: object
      properties:
        symbol:
          type: string
        bids:
          type: array
          items:
            $ref: '#/components/schemas/OrderBookLevel'
        asks:
          type: array
          items:
            $ref: '#/components/schemas/OrderBookLevel'
        last_update_id:
          type: integer
          nullable: true
    OHLCVBar:
      type: object
      properties:
        open_time:
          type: integer
          description: Unix ms timestamp
        open:
          type: number
        high:
          type: number
        low:
          type: number
        close:
          type: number
        volume:
          type: number
    OrderRequest:
      type: object
      required: [symbol, side, order_type, quantity]
      properties:
        symbol:
          type: string
        side:
          type: string
          enum: [buy, sell]
        order_type:
          type: string
          enum: [market, limit]
        quantity:
          type: string
        price:
          type: string
          nullable: true
    OrderResponse:
      type: object
      properties:
        order_id:
          type: string
        symbol:
          type: string
        side:
          type: string
        order_type:
          type: string
        quantity:
          type: string
        price:
          type: string
          nullable: true
        status:
          type: string
        exchange:
          type: string
        placed_at:
          type: string
          format: date-time
    Error:
      type: object
      properties:
        detail:
          type: string
security:
  - bearerAuth: []
paths:
  /health:
    get:
      operationId: health
      summary: Liveness probe
      tags: [health]
      security: []
      responses:
        '200':
          description: Service is alive
  /ready:
    get:
      operationId: ready
      summary: Readiness probe
      tags: [health]
      security: []
      responses:
        '200':
          description: Service is ready

  # ── Exchanges ─────────────────────────────────────────────────────────────
  /api/v1/exchanges:
    get:
      operationId: listExchanges
      summary: List available exchanges
      tags: [exchanges]
      security: []
      responses:
        '200':
          description: Available exchange names
          content:
            application/json:
              schema:
                type: object
                properties:
                  exchanges:
                    type: array
                    items:
                      type: string
                    example: [binance, gateio]
  /api/v1/exchanges/{exchange}/ping:
    get:
      operationId: pingExchange
      summary: Ping an exchange to check connectivity
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
            example: binance
      responses:
        '200':
          description: Ping result
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
  /api/v1/exchanges/{exchange}/symbols:
    get:
      operationId: getSymbols
      summary: Get tradeable symbols for an exchange
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Symbol list
          content:
            application/json:
              schema:
                type: object
                properties:
                  symbols:
                    type: array
                    items:
                      type: string
  /api/v1/exchanges/{exchange}/ticker/{symbol}:
    get:
      operationId: getTicker
      summary: Get current ticker for a symbol
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
        - name: symbol
          in: path
          required: true
          schema:
            type: string
            example: BTCUSDT
      responses:
        '200':
          description: Ticker data
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Ticker'
  /api/v1/exchanges/{exchange}/orderbook/{symbol}:
    get:
      operationId: getOrderbook
      summary: Get order book snapshot for a symbol
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
        - name: symbol
          in: path
          required: true
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
            default: 100
            minimum: 1
            maximum: 5000
      responses:
        '200':
          description: Order book snapshot
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderBookSnapshot'
  /api/v1/exchanges/{exchange}/balance:
    get:
      operationId: getBalance
      summary: Get account balance (requires auth)
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Asset balances
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
                example:
                  BTC: "0.12345678"
                  USDT: "1000.00"
  /api/v1/exchanges/{exchange}/ohlcv/{symbol}:
    get:
      operationId: getOHLCV
      summary: Get OHLCV candlestick data
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
        - name: symbol
          in: path
          required: true
          schema:
            type: string
        - name: interval
          in: query
          schema:
            type: string
            default: 1h
            example: 1h
        - name: limit
          in: query
          schema:
            type: integer
            default: 500
      responses:
        '200':
          description: OHLCV bars
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OHLCVBar'

  # ── Orders ────────────────────────────────────────────────────────────────
  /api/v1/exchanges/{exchange}/orders:
    post:
      operationId: placeOrder
      summary: Place an order on an exchange
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderRequest'
      responses:
        '201':
          description: Order placed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
        '422':
          description: Validation error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
    get:
      operationId: getOpenOrders
      summary: Get open orders on an exchange
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
        - name: symbol
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Open orders
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/OrderResponse'
  /api/v1/exchanges/{exchange}/orders/{symbol}/{order_id}:
    get:
      operationId: getOrder
      summary: Get a specific order
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
        - name: symbol
          in: path
          required: true
          schema:
            type: string
        - name: order_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Order details
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderResponse'
        '404':
          description: Not found
    delete:
      operationId: cancelOrder
      summary: Cancel an order
      tags: [exchanges]
      parameters:
        - name: exchange
          in: path
          required: true
          schema:
            type: string
        - name: symbol
          in: path
          required: true
          schema:
            type: string
        - name: order_id
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: Cancellation result
          content:
            application/json:
              schema:
                type: object

  # ── Audit ─────────────────────────────────────────────────────────────────
  /api/v1/audit/orders:
    get:
      operationId: listAuditLogs
      summary: List order audit logs
      tags: [audit]
      parameters:
        - name: exchange
          in: query
          schema:
            type: string
        - name: symbol
          in: query
          schema:
            type: string
        - name: page
          in: query
          schema:
            type: integer
            default: 1
        - name: size
          in: query
          schema:
            type: integer
            default: 50
      responses:
        '200':
          description: Audit log entries
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: integer
                        action:
                          type: string
                        exchange:
                          type: string
                        symbol:
                          type: string
                        status:
                          type: string
                        created_at:
                          type: string
                          format: date-time

  # ── Streams (WebSocket) ───────────────────────────────────────────────────
  /api/v1/streams/status:
    get:
      operationId: streamStatus
      summary: Get WebSocket stream status
      tags: [streams]
      responses:
        '200':
          description: Stream status
          content:
            application/json:
              schema:
                type: object

  # ── VNStock ───────────────────────────────────────────────────────────────
  /api/v1/vnstock/symbols:
    get:
      operationId: listVNStockSymbols
      summary: List available VNStock symbols
      tags: [vnstock]
      security: []
      responses:
        '200':
          description: VNStock symbol list
          content:
            application/json:
              schema:
                type: object
                properties:
                  symbols:
                    type: array
                    items:
                      type: string
