# Dexorder Research API Reference

This file contains the complete Python API source code with full docstrings.
These files are copied verbatim from `sandbox/dexorder/api/`.

The API provides access to market data and charting capabilities for research scripts.

---

## Overview

Research scripts access the API via:
```python
from dexorder.api import get_api
api = get_api()
```

The API instance provides:
- `api.data` - DataAPI for fetching OHLC market data
- `api.charting` - ChartingAPI for creating financial charts

---

## Complete API Source Code

The following sections contain the verbatim Python source files with complete
type hints, docstrings, and examples.


### api.py
```python
"""
Main Dexorder API - provides access to market data and charting.
"""

import logging

from .charting_api import ChartingAPI
from .data_api import DataAPI

log = logging.getLogger(__name__)


class API:
    """
    Main API for accessing market data and creating charts.

    This is the primary interface for research scripts and trading strategies.
    Access this via get_api() in research scripts.

    Attributes:
        data: DataAPI for fetching historical and current market data
        charting: ChartingAPI for creating candlestick charts and visualizations

    Example:
        from dexorder.api import get_api
        import asyncio

        api = get_api()

        # Fetch data
        df = asyncio.run(api.data.historical_ohlc(
            ticker="BTC/USDT.BINANCE",
            period_seconds=3600,
            start_time="2021-12-20",
            end_time="2021-12-21"
        ))

        # Create chart
        fig, ax = api.charting.plot_ohlc(df, title="BTC/USDT 1H")
    """

    def __init__(self, charting: ChartingAPI, data: DataAPI):
        self.charting: ChartingAPI = charting
        self.data: DataAPI = data
```


### data_api.py
```python
from abc import ABC, abstractmethod
from typing import Optional, List

import pandas as pd

from dexorder.utils import TimestampInput


class DataAPI(ABC):
    """
    API for accessing market data.

    Provides methods to query OHLC (Open, High, Low, Close) candlestick data
    for cryptocurrency markets.
    """

    @abstractmethod
    async def historical_ohlc(
        self,
        ticker: str,
        period_seconds: int,
        start_time: TimestampInput,
        end_time: TimestampInput,
        extra_columns: Optional[List[str]] = None,
    ) -> pd.DataFrame:
        """
        Fetch historical OHLC candlestick data for a market.

        Args:
            ticker: Market identifier in format "MARKET.EXCHANGE"
                   Examples: "BTC/USDT.BINANCE", "ETH/USD.COINBASE"
            period_seconds: Candle period in seconds
                   Common values:
                   - 60 (1 minute)
                   - 300 (5 minutes)
                   - 900 (15 minutes)
                   - 3600 (1 hour)
                   - 86400 (1 day)
                   - 604800 (1 week)
            start_time: Start of time range. Accepts:
                       - Unix timestamp in seconds (int/float): 1640000000
                       - Date string: "2021-12-20" or "2021-12-20 12:00:00"
                       - datetime object: datetime(2021, 12, 20)
                       - pandas Timestamp: pd.Timestamp("2021-12-20")
            end_time: End of time range. Same formats as start_time.
            extra_columns: Optional additional columns to include beyond the standard
                          OHLC columns. Available options:
                          - "volume" - Total volume (decimal float)
                          - "buy_vol" - Buy-side volume (decimal float)
                          - "sell_vol" - Sell-side volume (decimal float)
                          - "open_time", "high_time", "low_time", "close_time" (timestamps)
                          - "open_interest" (for futures markets)
                          - "ticker", "period_seconds"

        Returns:
            DataFrame with candlestick data sorted by timestamp (ascending).
            Standard columns (always included):
            - timestamp: Period start time in nanoseconds
            - open: Opening price (decimal float)
            - high: Highest price (decimal float)
            - low: Lowest price (decimal float)
            - close: Closing price (decimal float)

            Plus any columns specified in extra_columns.

            All prices and volumes are automatically converted to decimal floats
            using market metadata. No manual conversion is needed.

            Returns empty DataFrame if no data is available.

        Examples:
            # Basic OHLC with Unix timestamp
            df = await api.historical_ohlc(
                ticker="BTC/USDT.BINANCE",
                period_seconds=3600,
                start_time=1640000000,
                end_time=1640086400
            )

            # Using date strings with volume
            df = await api.historical_ohlc(
                ticker="BTC/USDT.BINANCE",
                period_seconds=3600,
                start_time="2021-12-20",
                end_time="2021-12-21",
                extra_columns=["volume"]
            )

            # Using datetime objects
            from datetime import datetime
            df = await api.historical_ohlc(
                ticker="ETH/USD.COINBASE",
                period_seconds=300,
                start_time=datetime(2021, 12, 20, 9, 30),
                end_time=datetime(2021, 12, 20, 16, 30),
                extra_columns=["volume", "buy_vol", "sell_vol"]
            )
        """
        pass

    @abstractmethod
    async def latest_ohlc(
        self,
        ticker: str,
        period_seconds: int,
        length: int = 1,
        extra_columns: Optional[List[str]] = None,
    ) -> pd.DataFrame:
        """
        Query the most recent OHLC candles for a ticker.

        This method fetches the latest N completed candles without needing to
        specify exact timestamps. Useful for real-time analysis and indicators.

        Args:
            ticker: Market identifier in format "MARKET.EXCHANGE"
                   Examples: "BTC/USDT.BINANCE", "ETH/USD.COINBASE"
            period_seconds: OHLC candle period in seconds
                   Common values: 60 (1m), 300 (5m), 900 (15m), 3600 (1h),
                                 86400 (1d), 604800 (1w)
            length: Number of most recent candles to return (default: 1)
            extra_columns: Optional list of additional column names to include.
                          Same column options as historical_ohlc:
                          - "volume", "buy_vol", "sell_vol"
                          - "open_time", "high_time", "low_time", "close_time"
                          - "open_interest", "ticker", "period_seconds"

        Returns:
            Pandas DataFrame with the same column structure as historical_ohlc,
            containing the N most recent completed candles sorted by timestamp.
            Returns empty DataFrame if no data is available.

        Examples:
            # Get the last candle
            df = await api.latest_ohlc(
                ticker="BTC/USDT.BINANCE",
                period_seconds=3600
            )
            # Returns: timestamp, open, high, low, close

            # Get the last 50 5-minute candles with volume
            df = await api.latest_ohlc(
                ticker="ETH/USD.COINBASE",
                period_seconds=300,
                length=50,
                extra_columns=["volume", "buy_vol", "sell_vol"]
            )

            # Get recent candles with all timing data
            df = await api.latest_ohlc(
                ticker="BTC/USDT.BINANCE",
                period_seconds=60,
                length=100,
                extra_columns=["open_time", "high_time", "low_time", "close_time"]
            )

        Note:
            This method returns only completed candles. The current (incomplete)
            candle is not included.
        """
        pass

```


### charting_api.py
```python
import logging
from abc import abstractmethod, ABC
from typing import Optional, Tuple, List

import pandas as pd
from matplotlib import pyplot as plt
from matplotlib.figure import Figure


class ChartingAPI(ABC):
    """
    API for creating financial charts and visualizations.

    Provides methods to create candlestick charts, add technical indicator panels,
    and build custom visualizations. All figures are automatically captured and
    returned to the client as images.

    Basic workflow:
    1. Create a chart with plot_ohlc() → returns Figure and Axes
    2. Optionally overlay indicators on the main axes (e.g., moving averages)
    3. Optionally add indicator panels below with add_indicator_panel()
    4. Figures are automatically captured (no need to save manually)
    """

    @abstractmethod
    def plot_ohlc(
        self,
        df: pd.DataFrame,
        title: Optional[str] = None,
        volume: bool = False,
        style: str = "charles",
        figsize: Tuple[int, int] = (12, 8),
        **kwargs
    ) -> Tuple[Figure, plt.Axes]:
        """
        Create a candlestick chart from OHLC data.

        Args:
            df: DataFrame with OHLC data. Required columns: open, high, low, close.
               Column names are case-insensitive.
            title: Chart title (optional)
            volume: If True, shows volume bars below the candlesticks (requires 'volume' column)
            style: Visual style for the chart. Available styles:
                  "charles" (default), "binance", "blueskies", "brasil", "checkers",
                  "classic", "mike", "nightclouds", "sas", "starsandstripes", "yahoo"
            figsize: Figure size as (width, height) in inches. Default: (12, 8)
            **kwargs: Additional styling arguments

        Returns:
            Tuple of (Figure, Axes):
            - Figure: matplotlib Figure object
            - Axes: Main candlestick axes (use for overlaying indicators)

        Examples:
            # Basic chart
            fig, ax = api.plot_ohlc(df)

            # With volume and title
            fig, ax = api.plot_ohlc(
                df,
                title="BTC/USDT 1H",
                volume=True,
                style="binance"
            )

            # Overlay moving average
            # NOTE: mplfinance uses integer x-positions (0..N-1) internally,
            # so overlays must use range(len(df)), not df.index.
            fig, ax = api.plot_ohlc(df)
            ax.plot(range(len(df)), df['sma_20'], label="SMA 20", color="blue")
            ax.legend()
        """
        pass

    @abstractmethod
    def add_indicator_panel(
        self,
        fig: Figure,
        df: pd.DataFrame,
        columns: Optional[List[str]] = None,
        ylabel: Optional[str] = None,
        height_ratio: float = 0.3,
        ylim: Optional[Tuple[float, float]] = None,
        **kwargs
    ) -> plt.Axes:
        """
        Add an indicator panel below the chart with time-aligned x-axis.

        Use this to display indicators that should be shown separately from the
        price chart (e.g., RSI, MACD, volume).

        Args:
            fig: Figure object from plot_ohlc()
            df: DataFrame with indicator data (must have same index as OHLC data)
            columns: Column names to plot. If None, plots all numeric columns.
            ylabel: Y-axis label (e.g., "RSI", "MACD")
            height_ratio: Panel height relative to main chart (default: 0.3 = 30%)
            ylim: Y-axis limits as (min, max). If None, auto-scales.
            **kwargs: Line styling options (color, linewidth, linestyle, alpha)

        Returns:
            Axes object for the new panel (use for further customization)

        Examples:
            # Add RSI panel with reference lines
            fig, ax = api.plot_ohlc(df)
            rsi_ax = api.add_indicator_panel(
                fig, df,
                columns=["rsi"],
                ylabel="RSI",
                ylim=(0, 100)
            )
            rsi_ax.axhline(30, color='green', linestyle='--', alpha=0.5)
            rsi_ax.axhline(70, color='red', linestyle='--', alpha=0.5)

            # Add MACD panel
            fig, ax = api.plot_ohlc(df)
            api.add_indicator_panel(
                fig, df,
                columns=["macd", "macd_signal"],
                ylabel="MACD"
            )
        """
        pass

    @abstractmethod
    def create_figure(
        self,
        figsize: Tuple[int, int] = (12, 8),
        style: str = "charles"
    ) -> Tuple[Figure, plt.Axes]:
        """
        Create a styled figure for custom visualizations.

        Use this when you want to create charts other than candlesticks
        (e.g., histograms, scatter plots, heatmaps).

        Args:
            figsize: Figure size as (width, height) in inches. Default: (12, 8)
            style: Style name for consistent theming. Default: "charles"

        Returns:
            Tuple of (Figure, Axes) ready for plotting

        Examples:
            # Histogram
            fig, ax = api.create_figure()
            ax.hist(returns, bins=50)
            ax.set_title("Return Distribution")

            # Heatmap
            fig, ax = api.create_figure(figsize=(10, 10))
            import seaborn as sns
            sns.heatmap(correlation_matrix, ax=ax)
            ax.set_title("Correlation Matrix")
        """
        pass
```


### __init__.py
```python
"""
Dexorder API - market data and charting for research and trading.

For research scripts, import and use get_api() to access the API:

    from dexorder.api import get_api
    import asyncio

    api = get_api()
    df = asyncio.run(api.data.historical_ohlc(...))
    fig, ax = api.charting.plot_ohlc(df)
"""

import logging
import threading
from typing import Optional

from dexorder.api.api import API
from dexorder.api.charting_api import ChartingAPI
from dexorder.api.data_api import DataAPI

log = logging.getLogger(__name__)

# Global API instance - managed by main.py
_global_api: Optional[API] = None

# Thread-local API — used by harness threads so they don't overwrite the global
_thread_local = threading.local()


def get_api() -> API:
    """
    Get the API instance for accessing market data and charts.

    Use this in research scripts to access the data and charting APIs.

    Returns:
        API instance with data and charting capabilities

    Raises:
        RuntimeError: If called before API initialization (should not happen in research scripts)

    Example:
        from dexorder.api import get_api
        import asyncio

        api = get_api()

        # Fetch data
        df = asyncio.run(api.data.historical_ohlc(
            ticker="BTC/USDT.BINANCE",
            period_seconds=3600,
            start_time="2021-12-20",
            end_time="2021-12-21"
        ))

        # Create chart
        fig, ax = api.charting.plot_ohlc(df, title="BTC/USDT")
    """
    # Thread-local takes priority (set by harness threads)
    api = getattr(_thread_local, 'api', None)
    if api is not None:
        return api
    if _global_api is None:
        raise RuntimeError("API not initialized")
    return _global_api


def set_api(api: API) -> None:
    """Set the API instance.

    When called from the main thread, sets the global API used by all threads.
    When called from a non-main thread (e.g. harness threads), sets a thread-local
    API so the global is not overwritten.
    """
    if threading.current_thread() is threading.main_thread():
        global _global_api
        _global_api = api
    else:
        _thread_local.api = api


__all__ = ['API', 'ChartingAPI', 'DataAPI', 'get_api', 'set_api']
```


---

For practical usage patterns and complete working examples, see `usage-examples.md`.
