329 lines
10 KiB
Markdown
329 lines
10 KiB
Markdown
---
|
|
description: "Example research scripts showing common patterns for data retrieval, statistical analysis, and visualization."
|
|
---
|
|
|
|
# Research Script API Usage
|
|
|
|
See [`api-reference.md`](api-reference.md) for the full DataAPI and ChartingAPI source with all method signatures and docstrings. See [`pandas-ta-reference.md`](pandas-ta-reference.md) for the indicator catalog.
|
|
|
|
Research scripts executed via the `ExecuteResearch` MCP tool have access to the global API instance, which provides both data fetching and charting capabilities.
|
|
|
|
## Accessing the API
|
|
|
|
```python
|
|
from dexorder.api import get_api
|
|
import asyncio
|
|
|
|
# Get the global API instance
|
|
api = get_api()
|
|
```
|
|
|
|
## Using the Data API
|
|
|
|
The data API provides access to historical OHLC (Open, High, Low, Close) market data with smart caching via Iceberg.
|
|
|
|
### Fetching Historical Data
|
|
|
|
The API accepts flexible timestamp formats for convenience:
|
|
|
|
```python
|
|
from dexorder.api import get_api
|
|
import asyncio
|
|
from datetime import datetime
|
|
|
|
api = get_api()
|
|
|
|
# Method 1: Using Unix timestamps (seconds)
|
|
# 1609459200 = 2021-01-01, 1735689600 = 2025-01-01
|
|
df = asyncio.run(api.data.historical_ohlc(
|
|
ticker="BTC/USDT.BINANCE",
|
|
period_seconds=3600, # 1 hour candles
|
|
start_time=1609459200, # 2021-01-01
|
|
end_time=1735689600, # 2025-01-01 (~4 years, ~35,000 bars)
|
|
extra_columns=["volume"]
|
|
))
|
|
|
|
# Method 2: Using date strings
|
|
df = asyncio.run(api.data.historical_ohlc(
|
|
ticker="BTC/USDT.BINANCE",
|
|
period_seconds=3600,
|
|
start_time="2021-01-01",
|
|
end_time="2025-01-01", # ~4 years of 1h bars ≈ 35,000 bars
|
|
extra_columns=["volume"]
|
|
))
|
|
|
|
# Method 3: Using date strings with time
|
|
df = asyncio.run(api.data.historical_ohlc(
|
|
ticker="BTC/USDT.BINANCE",
|
|
period_seconds=3600,
|
|
start_time="2021-01-01 00:00:00",
|
|
end_time="2025-01-01 00:00:00",
|
|
extra_columns=["volume"]
|
|
))
|
|
|
|
# Method 4: Using datetime objects
|
|
from datetime import datetime, timedelta
|
|
end_time = datetime.now()
|
|
start_time = end_time - timedelta(days=4*365) # 4 years back
|
|
df = asyncio.run(api.data.historical_ohlc(
|
|
ticker="BTC/USDT.BINANCE",
|
|
period_seconds=3600,
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
extra_columns=["volume"]
|
|
))
|
|
|
|
print(f"Loaded {len(df)} candles from {df.index[0]} to {df.index[-1]}")
|
|
print(df.head())
|
|
```
|
|
|
|
### Available Extra Columns
|
|
|
|
All columns below are fully populated for Binance data. Other exchanges provide only `volume`.
|
|
|
|
- `"volume"` - Total base-asset volume
|
|
- `"buy_vol"` - Taker buy volume (base asset) — order flow long pressure
|
|
- `"sell_vol"` - Taker sell volume (base asset) — order flow short pressure
|
|
- `"quote_volume"` - Total quote-asset volume (e.g. USDT traded)
|
|
- `"num_trades"` - Number of individual trades in the candle
|
|
- `"open_time"`, `"close_time"` - Exact candle open/close timestamps (Binance only)
|
|
- `"high_time"`, `"low_time"` - Not provided by any exchange (always null)
|
|
- `"open_interest"` - Open interest (futures only)
|
|
- `"ticker"` - Market identifier
|
|
- `"period_seconds"` - Period in seconds
|
|
|
|
## Building a Scanner Universe with get_ticker_24h
|
|
|
|
**Always pre-filter symbols before fetching OHLC data for scanners.** Fetching OHLC for all ~1800 Binance symbols would exhaust the 2M-bar per-script budget instantly. Use `get_ticker_24h` to get a ranked list of all symbols for free (no OHLC budget cost), then run per-symbol analysis only on the filtered set.
|
|
|
|
```python
|
|
from dexorder.api import get_api
|
|
import asyncio
|
|
|
|
api = get_api()
|
|
|
|
# Get top 50 most liquid Binance spot symbols (no OHLC budget used)
|
|
universe = asyncio.run(api.data.get_ticker_24h(
|
|
"BINANCE",
|
|
limit=50,
|
|
market_type="spot",
|
|
min_std_quote_volume=10_000_000 # $10M+ daily volume
|
|
))
|
|
print(f"Universe: {len(universe)} symbols")
|
|
print(universe[["ticker", "std_quote_volume", "price_change_pct"]].head(10))
|
|
|
|
# Now fetch OHLC only for these symbols
|
|
tickers = universe["ticker"].tolist()
|
|
results = {}
|
|
for ticker in tickers:
|
|
df = asyncio.run(api.data.historical_ohlc(
|
|
ticker=ticker,
|
|
period_seconds=3600,
|
|
start_time="2024-01-01",
|
|
end_time="2025-01-01",
|
|
extra_columns=["volume"]
|
|
))
|
|
print(f"[Data] {ticker}: {len(df)} bars")
|
|
results[ticker] = df
|
|
```
|
|
|
|
### get_ticker_24h filter parameters
|
|
|
|
```python
|
|
# All BTC pairs on Binance (spot + perp)
|
|
df = asyncio.run(api.data.get_ticker_24h("BINANCE", base_asset_contains="BTC"))
|
|
|
|
# Top 100 perp markets with at least $50M daily volume
|
|
df = asyncio.run(api.data.get_ticker_24h(
|
|
"BINANCE",
|
|
limit=100,
|
|
market_type="perp",
|
|
min_std_quote_volume=50_000_000
|
|
))
|
|
|
|
# All Coinbase symbols (for a cross-exchange scan)
|
|
df = asyncio.run(api.data.get_ticker_24h("COINBASE"))
|
|
```
|
|
|
|
The returned DataFrame is sorted by `std_quote_volume` (USD-normalized volume) descending. Symbols without a USD conversion path have `std_quote_volume = NaN` and appear last. Columns: `ticker`, `exchange_id`, `base_asset`, `quote_asset`, `last_price`, `price_change_pct`, `quote_volume_24h`, `std_quote_volume`, `bid_price`, `ask_price`, `open_24h`, `high_24h`, `low_24h`, `volume_24h`, `num_trades`, `timestamp_ms`.
|
|
|
|
## Using the Charting API
|
|
|
|
The charting API provides styled financial charts with OHLC candlesticks and technical indicators.
|
|
|
|
### Creating a Basic Candlestick Chart
|
|
|
|
```python
|
|
from dexorder.api import get_api
|
|
import asyncio
|
|
from datetime import datetime
|
|
|
|
api = get_api()
|
|
|
|
# Fetch data
|
|
df = asyncio.run(api.data.historical_ohlc(
|
|
ticker="BTC/USDT.BINANCE",
|
|
period_seconds=3600,
|
|
start_time="2021-01-01",
|
|
end_time="2025-01-01", # ~4 years of 1h bars
|
|
extra_columns=["volume"]
|
|
))
|
|
|
|
# Create candlestick chart (synchronous)
|
|
fig, ax = api.charting.plot_ohlc(
|
|
df,
|
|
title="BTC/USDT 1H",
|
|
volume=True, # Show volume bars
|
|
style="charles" # Chart style
|
|
)
|
|
|
|
# The figure is automatically captured and returned to the MCP client
|
|
```
|
|
|
|
### Adding Indicator Panels
|
|
|
|
Use **pandas-ta** for all indicator calculations. Do not write manual rolling/ewm implementations.
|
|
|
|
```python
|
|
from dexorder.api import get_api
|
|
import asyncio
|
|
import pandas_ta as ta
|
|
|
|
api = get_api()
|
|
|
|
# Fetch data
|
|
df = asyncio.run(api.data.historical_ohlc(
|
|
ticker="BTC/USDT.BINANCE",
|
|
period_seconds=3600,
|
|
start_time="2021-01-01",
|
|
end_time="2025-01-01"
|
|
))
|
|
|
|
# Calculate indicators using pandas-ta
|
|
df['sma_20'] = ta.sma(df['close'], length=20)
|
|
df['rsi'] = ta.rsi(df['close'], length=14)
|
|
|
|
# Create chart
|
|
fig, ax = api.charting.plot_ohlc(df, title="BTC/USDT with SMA")
|
|
|
|
# Overlay the SMA on the price chart
|
|
# NOTE: mplfinance uses integer x-positions (0..N-1); use range(len(df)), not df.index.
|
|
ax.plot(range(len(df)), df['sma_20'], label="SMA 20", color="blue", linewidth=2)
|
|
ax.legend()
|
|
|
|
# Add RSI indicator panel below
|
|
rsi_ax = api.charting.add_indicator_panel(
|
|
fig, df,
|
|
columns=["rsi"],
|
|
ylabel="RSI",
|
|
ylim=(0, 100)
|
|
)
|
|
rsi_ax.axhline(70, color='red', linestyle='--', alpha=0.5)
|
|
rsi_ax.axhline(30, color='green', linestyle='--', alpha=0.5)
|
|
```
|
|
|
|
### Multi-Output Indicators
|
|
|
|
Some pandas-ta indicators return a DataFrame. Extract the columns you need:
|
|
|
|
```python
|
|
import pandas_ta as ta
|
|
|
|
# MACD returns: MACD_12_26_9, MACDh_12_26_9, MACDs_12_26_9
|
|
macd_df = ta.macd(df['close'], fast=12, slow=26, signal=9)
|
|
df['macd'] = macd_df.iloc[:, 0] # MACD line
|
|
df['macd_hist'] = macd_df.iloc[:, 1] # Histogram
|
|
df['macd_signal'] = macd_df.iloc[:, 2] # Signal line
|
|
|
|
# Bollinger Bands returns: BBL, BBM, BBU, BBB, BBP
|
|
bb_df = ta.bbands(df['close'], length=20, std=2.0)
|
|
df['bb_upper'] = bb_df.iloc[:, 2] # BBU
|
|
df['bb_mid'] = bb_df.iloc[:, 1] # BBM
|
|
df['bb_lower'] = bb_df.iloc[:, 0] # BBL
|
|
|
|
# Stochastic returns: STOCHk, STOCHd
|
|
stoch_df = ta.stoch(df['high'], df['low'], df['close'], k=14, d=3, smooth_k=3)
|
|
df['stoch_k'] = stoch_df.iloc[:, 0]
|
|
df['stoch_d'] = stoch_df.iloc[:, 1]
|
|
|
|
# ATR (uses high, low, close)
|
|
df['atr'] = ta.atr(df['high'], df['low'], df['close'], length=14)
|
|
```
|
|
|
|
## Complete Example
|
|
|
|
```python
|
|
from dexorder.api import get_api
|
|
import asyncio
|
|
import pandas_ta as ta
|
|
|
|
# Get API instance
|
|
api = get_api()
|
|
|
|
# Fetch historical data — use max history for research (target 100k-200k bars)
|
|
from datetime import datetime, timedelta
|
|
end_time = datetime.now()
|
|
start_time = end_time - timedelta(days=3*365) # 3 years of 1h bars ≈ 26,000 bars
|
|
|
|
df = asyncio.run(api.data.historical_ohlc(
|
|
ticker="BTC/USDT.BINANCE",
|
|
period_seconds=3600, # 1 hour
|
|
start_time=start_time,
|
|
end_time=end_time,
|
|
extra_columns=["volume"]
|
|
))
|
|
print(f"[Data] {len(df)} bars | {df.index[0]} → {df.index[-1]} | period=3600s")
|
|
|
|
# Add moving averages using pandas-ta
|
|
df['sma_20'] = ta.sma(df['close'], length=20)
|
|
df['ema_50'] = ta.ema(df['close'], length=50)
|
|
|
|
# Create chart with volume
|
|
fig, ax = api.charting.plot_ohlc(
|
|
df,
|
|
title="BTC/USDT Analysis",
|
|
volume=True,
|
|
style="charles"
|
|
)
|
|
|
|
# Overlay moving averages
|
|
# NOTE: mplfinance uses integer x-positions (0..N-1); use range(len(df)), not df.index.
|
|
ax.plot(range(len(df)), df['sma_20'], label="SMA 20", color="blue", linewidth=1.5)
|
|
ax.plot(range(len(df)), df['ema_50'], label="EMA 50", color="red", linewidth=1.5)
|
|
ax.legend()
|
|
|
|
# Print summary statistics
|
|
print(f"[Data] {len(df)} bars | {df.index[0]} → {df.index[-1]} | period=3600s")
|
|
print(f"High: {df['high'].max()}")
|
|
print(f"Low: {df['low'].min()}")
|
|
print(f"Mean Volume: {df['volume'].mean():.2f}")
|
|
```
|
|
|
|
## Notes
|
|
|
|
- **Async vs Sync**: Data API methods are async and require `asyncio.run()`. Charting API methods are synchronous.
|
|
- **Figure Capture**: All matplotlib figures created during script execution are automatically captured and returned as PNG images.
|
|
- **Print Statements**: All `print()` output is captured and returned as text content.
|
|
- **Errors**: Exceptions are caught and reported in the execution results.
|
|
- **Timestamps**: The API accepts flexible timestamp formats:
|
|
- Unix timestamps in **seconds** (int or float) - e.g., `1640000000`
|
|
- Date strings - e.g., `"2021-12-20"` or `"2021-12-20 12:00:00"`
|
|
- datetime objects - e.g., `datetime(2021, 12, 20)`
|
|
- pandas Timestamp objects
|
|
- Internally, the system uses microseconds since epoch, but you don't need to worry about this conversion.
|
|
- **Price/Volume Values**: All prices and volumes are returned as decimal floats, automatically converted from internal storage format using market metadata. No manual conversion is needed.
|
|
|
|
## Available Chart Styles
|
|
|
|
- `"charles"` (default)
|
|
- `"binance"`
|
|
- `"blueskies"`
|
|
- `"brasil"`
|
|
- `"checkers"`
|
|
- `"classic"`
|
|
- `"mike"`
|
|
- `"nightclouds"`
|
|
- `"sas"`
|
|
- `"starsandstripes"`
|
|
- `"yahoo"`
|