Building a crypto trading bot is not just about writing a script that buys when price goes up and sells when price goes down.
That kind of bot may work for a simple demo, but it is usually not enough for real crypto markets, especially if the bot trades futures, perpetual contracts, or leveraged positions.
Crypto markets are heavily influenced by derivatives. A large price move may be caused by spot buying, but it may also be caused by:
- Open interest expansion
- Funding rate imbalance
- Short liquidations
- Long liquidations
- Leverage build-up
- Forced deleveraging
- Order book liquidity gaps
- Aggressive taker buy or sell pressure
- Cross-exchange positioning
This is why a serious crypto trading bot needs more than price data. It needs market structure data.
CoinGlass API is useful in this context because it provides access to key crypto derivatives data such as open interest, funding rates, liquidations, long/short ratios, order book data, options data, ETF flow data, and other market indicators. CoinGlass API V4 is the current recommended version, while V1–V3 are deprecated and mainly kept for backward compatibility. ([coinglass][1])
In this guide, we will walk through how to build a crypto trading bot using CoinGlass API as a market intelligence layer. The goal is not to build a perfect money-printing machine. The goal is to design a more market-aware trading bot that can understand when a signal is strong, when risk is elevated, and when it is better to stay out.
1. What Kind of Trading Bot Are We Building?
Before writing code, we need to define the bot.
A crypto trading bot can mean many different things:
| Bot Type | Description | Data Needed |
|---|---|---|
| Price alert bot | Sends alerts when price reaches a level | Price data |
| Trend-following bot | Buys breakouts and sells breakdowns | Price, volume, OI |
| Grid bot | Places buy and sell orders in a range | Price, volatility, risk filters |
| Funding rate bot | Monitors funding rate opportunities | Funding rate, OI, exchange data |
| Liquidation alert bot | Detects abnormal liquidation events | Liquidation data |
| Risk management bot | Reduces exposure during extreme market stress | OI, funding, liquidations |
| Quant strategy bot | Uses multiple factors to generate signals | Historical and real-time data |
In this article, we will build a derivatives-aware trading bot framework.
The bot will:
- Fetch market data from CoinGlass API
- Read open interest, funding rate, and liquidation data
- Convert raw data into trading features
- Generate market state signals
- Combine derivatives signals with a simple price signal
- Output a trading decision
- Adjust position size based on market risk
This is a realistic architecture because CoinGlass API is best used as a market intelligence layer, while exchange APIs are usually used as the execution layer.
2. CoinGlass API vs Exchange API
Many developers ask:
Why not just use Binance API, OKX API, Bybit API, or another exchange API?
The answer is simple: exchange APIs and CoinGlass API solve different problems.
| Function | Exchange API | CoinGlass API |
|---|---|---|
| Place orders | Yes | No |
| Manage account balance | Yes | No |
| Read current position | Yes | No |
| Get exchange-specific price | Yes | Sometimes, depending on endpoint |
| Compare multiple exchanges | Manual work needed | More suitable |
| Get aggregated derivatives data | Harder | Designed for this |
| Get funding rate context | Limited to exchange | Broader derivatives view |
| Get liquidation data | Exchange-specific or limited | More useful as an aggregated market signal |
| Build market structure signals | Requires heavy engineering | More direct |
| Execute trades | Yes | No |
A good trading system usually uses both:
Exchange API = execution layer
CoinGlass API = market intelligence layer
The exchange API answers:
Can I place this order?
What is my account balance?
What is my current position?
CoinGlass API helps answer:
Should I place this order?
Is the market crowded?
Is leverage building up?
Are traders being liquidated?
Is this breakout healthy?
That distinction is important. A trading bot should not only know how to trade. It should also know when not to trade.
3. Why CoinGlass API Is Useful for Trading Bots
CoinGlass provides a broad set of crypto market data. According to CoinGlass public API materials, its crypto API covers derivatives, spot, options, ETF markets, order book data, and market snapshot data such as price, volume, open interest, and funding rates. ([coinglass][2])
For trading bots, the most useful data categories are:
| Data Type | Why It Matters |
|---|---|
| Open Interest | Shows whether leveraged capital is entering or leaving |
| Funding Rate | Measures long/short cost and crowding |
| Liquidations | Shows forced position closures |
| Long/Short Ratio | Helps detect positioning imbalance |
| Taker Buy/Sell Volume | Shows aggressive buying or selling pressure |
| Order Book Data | Helps analyze liquidity and execution risk |
| Liquidation Heatmap | Helps identify potential liquidation zones |
| ETF Flow Data | Useful for broader market flow analysis |
| Options Data | Useful for volatility and institutional positioning |
CoinGlass API official materials list futures modules such as open interest, funding rate, liquidation data, global long/short ratios, top trader long/short ratios, and taker buy/sell volume. Some example endpoint categories include /api/futures/openInterest/ohlc-history, /api/futures/fundingRate/oi-weight-ohlc-history, and /api/futures/liquidation/aggregated-history. ([coinglass][3])
These data points help the bot understand market state instead of only reacting to price.
4. Trading Bot Architecture
A simple crypto trading bot architecture looks like this:
Data Layer
↓
Feature Layer
↓
Signal Layer
↓
Risk Layer
↓
Execution Layer
↓
Logging / Monitoring Layer
Let’s define each layer.
| Layer | Purpose |
|---|---|
| Data Layer | Fetch raw market data from APIs |
| Feature Layer | Convert raw data into useful indicators |
| Signal Layer | Generate buy, sell, or hold signals |
| Risk Layer | Adjust position size and filter bad trades |
| Execution Layer | Place orders through exchange API |
| Logging Layer | Store decisions, errors, and performance data |
CoinGlass API sits mainly in the Data Layer, but its output is used heavily in the Feature, Signal, and Risk layers.
A practical bot architecture may look like this:
CoinGlass API
- Open Interest
- Funding Rate
- Liquidation Data
- Long/Short Ratio
- Order Flow
Exchange API
- Price Candles
- Account Balance
- Order Placement
- Position Management
Trading Bot
- Feature Engineering
- Signal Generation
- Risk Filtering
- Position Sizing
- Execution
This article will focus on the CoinGlass API side and the strategy framework. You can connect the final decision output to your preferred exchange API.
5. Core Strategy Idea
A common beginner bot does this:
If price breaks above moving average → BUY
If price breaks below moving average → SELL
This is simple, but it ignores derivatives market structure.
A better bot does this:
If price gives BUY signal
AND funding rate is not extremely high
AND open interest supports the move
AND liquidation risk is not extreme
THEN allow the trade
Otherwise, reduce size or skip the trade
This is more realistic.
The bot does not simply ask:
Did price go up?
It asks:
Is this price move healthy?
Is leverage supporting it?
Is one side too crowded?
Is the market entering a liquidation cascade?
That is the main difference between a basic bot and a market-aware bot.
6. Key CoinGlass Data for the Bot
For this trading bot, we will focus on three core data types:
- Open Interest
- Funding Rate
- Liquidation Data
These three are enough to build a strong first version.
6.1 Open Interest
Open Interest, or OI, measures the total open futures or perpetual contract positions.
It helps answer:
Is new leverage entering the market?
| Price | Open Interest | Possible Interpretation |
|---|---|---|
| Price up | OI up | New positions support the move |
| Price up | OI down | Shorts may be closing |
| Price down | OI up | New shorts may be entering |
| Price down | OI down | Longs may be closing or liquidated |
| Price flat | OI up | Leverage is building before a possible breakout |
For bots, OI is useful because it helps confirm whether a price movement is supported by new market participation.
Example:
BTC price rises 3%.
Open interest also rises.
Funding rate remains neutral.
This may be a healthier bullish trend.
But:
BTC price rises 3%.
Open interest rises sharply.
Funding rate becomes extremely positive.
Long/short ratio becomes heavily long.
This may be a crowded long environment.
6.2 Funding Rate
Funding rate is the periodic payment between longs and shorts in perpetual futures.
| Funding Rate | Meaning |
|---|---|
| Positive | Longs pay shorts |
| Negative | Shorts pay longs |
| Extremely positive | Longs may be crowded |
| Extremely negative | Shorts may be crowded |
| Neutral | Market is more balanced |
Funding rate is not a direct buy or sell signal.
A common mistake is:
Funding high = short
Funding low = long
That is too simple.
A better interpretation is:
Funding high = long side may be crowded
Funding low = short side may be crowded
Funding rate is best used as a filter.
Examples:
| Price Signal | Funding Rate | Bot Action |
|---|---|---|
| BUY | Neutral | Allow trade |
| BUY | Extremely positive | Reduce size or skip |
| SELL | Neutral | Allow trade |
| SELL | Extremely negative | Reduce size or skip |
| BUY | Negative + short liquidations rising | Possible short squeeze setup |
6.3 Liquidation Data
Liquidation data shows forced position closures.
It helps answer:
Which side is being forced out?
| Liquidation Event | Interpretation |
|---|---|
| Long liquidation spike | Longs are being forced out |
| Short liquidation spike | Shorts are being squeezed |
| Both sides liquidated | Extreme volatility |
| Liquidations decline | Leverage pressure may be cooling |
| Liquidation spike + price recovery | Possible false breakdown or liquidity sweep |
Liquidation data is extremely useful for risk management.
A bot can use it to:
- Avoid trading during liquidation cascades
- Detect short squeeze conditions
- Detect long squeeze conditions
- Reduce position size during market stress
- Avoid buying or selling after a move is already exhausted
7. API Setup
CoinGlass API V4 uses the following base URL in public documentation and examples:
https://open-api-v4.coinglass.com
Requests generally use the CG-API-KEY header for authentication. CoinGlass documentation states that API V4 brings improved performance, faster response times, and optimized data retrieval. ([coinglass][4])
First, install the required Python packages:
pip install requests pandas python-dotenv
Create a .env file:
COINGLASS_API_KEY=your_api_key_here
Then create a Python file named:
bot.py
Basic API client:
import os
import requests
import pandas as pd
from dotenv import load_dotenv
load_dotenv()
BASE_URL = "https://open-api-v4.coinglass.com"
API_KEY = os.getenv("COINGLASS_API_KEY")
if not API_KEY:
raise RuntimeError("Missing COINGLASS_API_KEY environment variable")
HEADERS = {
"CG-API-KEY": API_KEY,
"Accept": "application/json"
}
def request_coinglass(endpoint, params=None):
"""
Send a GET request to CoinGlass API.
"""
url = f"{BASE_URL}{endpoint}"
response = requests.get(
url,
headers=HEADERS,
params=params,
timeout=10
)
response.raise_for_status()
return response.json()
This function will be reused for all CoinGlass API requests.
8. Add Safe Request Handling
Production bots should not crash because one API request fails.
Let’s improve the request function with retries:
import time
def safe_request_coinglass(endpoint, params=None, retries=3, sleep_seconds=2):
"""
Send a GET request with retry logic.
"""
last_error = None
for attempt in range(retries):
try:
return request_coinglass(endpoint, params)
except requests.RequestException as error:
last_error = error
print(f"Request failed: attempt {attempt + 1}/{retries}: {error}")
time.sleep(sleep_seconds)
raise last_error
This is important because live bots must handle:
- Network errors
- Timeout errors
- Temporary API issues
- Rate limits
- Invalid responses
- Missing data
A trading bot should fail safely, not blindly continue with broken data.
9. Fetch Open Interest Data
CoinGlass public API materials list Open Interest endpoints such as:
/api/futures/openInterest/ohlc-history
/api/futures/openInterest/aggregated-history
/api/futures/openInterest/exchange-list
For this example, we will use an OHLC-style history endpoint. Always verify endpoint names and parameters with the latest official documentation before production use.
def fetch_open_interest(symbol="BTC", interval="1h", limit=100):
endpoint = "/api/futures/openInterest/ohlc-history"
params = {
"symbol": symbol,
"interval": interval,
"limit": limit
}
return safe_request_coinglass(endpoint, params)
Convert the response into a DataFrame:
def to_dataframe(raw):
"""
Convert a CoinGlass API response to a pandas DataFrame.
Adjust this function based on the actual response shape.
"""
data = raw.get("data", [])
if isinstance(data, dict):
# Some APIs may return nested structures.
# Adjust based on actual response.
rows = data.get("list", [])
else:
rows = data
df = pd.DataFrame(rows)
if df.empty:
return df
if "time" in df.columns:
df["time"] = pd.to_datetime(df["time"], unit="ms", errors="coerce")
return df
Add OI features:
def add_open_interest_features(df):
data = df.copy()
# Adjust field names based on actual API response.
if "close" in data.columns:
data["oi_close"] = pd.to_numeric(data["close"], errors="coerce")
elif "openInterest" in data.columns:
data["oi_close"] = pd.to_numeric(data["openInterest"], errors="coerce")
else:
raise ValueError("No recognizable open interest field found")
data["oi_change"] = data["oi_close"].pct_change()
data["oi_change_24"] = data["oi_close"].pct_change(24)
return data
10. Fetch Funding Rate Data
CoinGlass public materials list funding rate endpoints such as:
/api/futures/fundingRate/ohlc-history
/api/futures/fundingRate/oi-weight-ohlc-history
/api/futures/fundingRate/exchange-list
A bot can use funding rate to detect crowded long or short conditions.
def fetch_funding_rate(symbol="BTC", interval="1h", limit=100):
endpoint = "/api/futures/fundingRate/oi-weight-ohlc-history"
params = {
"symbol": symbol,
"interval": interval,
"limit": limit
}
return safe_request_coinglass(endpoint, params)
Add funding rate features:
def zscore(series, window=24):
mean = series.rolling(window).mean()
std = series.rolling(window).std()
return (series - mean) / std
def add_funding_features(df, window=24):
data = df.copy()
# Adjust field name based on actual API response.
if "close" in data.columns:
data["funding_close"] = pd.to_numeric(data["close"], errors="coerce")
elif "fundingRate" in data.columns:
data["funding_close"] = pd.to_numeric(data["fundingRate"], errors="coerce")
else:
raise ValueError("No recognizable funding rate field found")
data["funding_z"] = zscore(data["funding_close"], window)
return data
Interpretation:
| Funding Z-score | Meaning |
|---|---|
| Above 2 | Extremely positive funding |
| 1 to 2 | Moderately positive funding |
| -1 to 1 | Neutral |
| -2 to -1 | Moderately negative funding |
| Below -2 | Extremely negative funding |
This lets the bot detect whether the market is unusually long-heavy or short-heavy.
11. Fetch Liquidation Data
CoinGlass public materials list liquidation endpoints such as:
/api/futures/liquidation/history
/api/futures/liquidation/aggregated-history
/api/futures/liquidation/heatmap/model2
For this example:
def fetch_liquidation_history(
symbol="BTC",
exchanges="Binance,OKX,Bybit",
interval="1h",
limit=100
):
endpoint = "/api/futures/liquidation/aggregated-history"
params = {
"exchange_list": exchanges,
"symbol": symbol,
"interval": interval,
"limit": limit
}
return safe_request_coinglass(endpoint, params)
Add liquidation features:
def add_liquidation_features(df, window=24):
data = df.copy()
rename_map = {
"longLiquidation": "long_liquidation",
"shortLiquidation": "short_liquidation",
"long_liq": "long_liquidation",
"short_liq": "short_liquidation"
}
data = data.rename(columns=rename_map)
if "long_liquidation" not in data.columns:
raise ValueError("No long liquidation field found")
if "short_liquidation" not in data.columns:
raise ValueError("No short liquidation field found")
data["long_liquidation"] = pd.to_numeric(
data["long_liquidation"],
errors="coerce"
)
data["short_liquidation"] = pd.to_numeric(
data["short_liquidation"],
errors="coerce"
)
data["long_liq_z"] = zscore(data["long_liquidation"], window)
data["short_liq_z"] = zscore(data["short_liquidation"], window)
data["total_liquidation"] = (
data["long_liquidation"] + data["short_liquidation"]
)
data["total_liq_z"] = zscore(data["total_liquidation"], window)
return data
Interpretation:
| Liquidation Signal | Meaning |
|---|---|
| Long liquidation z-score > 2 | Longs are being liquidated unusually |
| Short liquidation z-score > 2 | Shorts are being liquidated unusually |
| Total liquidation z-score > 3 | Extreme risk environment |
| Liquidation z-score near 0 | Normal environment |
12. Merge Data into One Market Table
Now we need to merge open interest, funding rate, and liquidation data by timestamp.
def prepare_time_column(df):
data = df.copy()
if "time" not in data.columns:
raise ValueError("Missing time column")
data = data.dropna(subset=["time"])
data = data.sort_values("time")
return data
def merge_market_data(oi_df, funding_df, liquidation_df):
oi = prepare_time_column(oi_df)
funding = prepare_time_column(funding_df)
liquidation = prepare_time_column(liquidation_df)
merged = pd.merge_asof(
oi,
funding,
on="time",
direction="nearest",
tolerance=pd.Timedelta("10min"),
suffixes=("_oi", "_funding")
)
merged = pd.merge_asof(
merged,
liquidation,
on="time",
direction="nearest",
tolerance=pd.Timedelta("10min")
)
return merged
The merged table may include:
| Column | Meaning |
|---|---|
| time | Timestamp |
| oi_close | Open interest value |
| oi_change | Short-term OI change |
| oi_change_24 | 24-period OI change |
| funding_close | Funding rate |
| funding_z | Funding rate z-score |
| long_liquidation | Long liquidation amount |
| short_liquidation | Short liquidation amount |
| long_liq_z | Long liquidation z-score |
| short_liq_z | Short liquidation z-score |
| total_liq_z | Total liquidation z-score |
This table becomes the bot’s derivatives market state table.
13. Build a Simple Price Signal
CoinGlass API can provide market data, but many bots still combine derivatives data with price signals.
For simplicity, let’s create a moving average signal.
In production, you may get price candles from:
- Your exchange API
- CoinGlass spot or futures market endpoints
- Your own database
- Another market data provider
Example:
def generate_price_signal(price_df):
"""
Simple moving average signal.
price_df must contain a 'close' column.
"""
data = price_df.copy()
data["close"] = pd.to_numeric(data["close"], errors="coerce")
data["ma_fast"] = data["close"].rolling(20).mean()
data["ma_slow"] = data["close"].rolling(60).mean()
latest = data.iloc[-1]
if latest["ma_fast"] > latest["ma_slow"]:
return "BUY"
if latest["ma_fast"] < latest["ma_slow"]:
return "SELL"
return "HOLD"
This signal is intentionally simple. The purpose of the article is not to create a perfect price model, but to show how CoinGlass API data can improve the bot’s market awareness.
14. Build a Derivatives Signal
Now let’s convert the merged derivatives data into a market state signal.
def classify_derivatives_state(row):
funding_z = row.get("funding_z", 0)
long_liq_z = row.get("long_liq_z", 0)
short_liq_z = row.get("short_liq_z", 0)
total_liq_z = row.get("total_liq_z", 0)
oi_change = row.get("oi_change", 0)
if pd.isna(funding_z):
funding_z = 0
if pd.isna(long_liq_z):
long_liq_z = 0
if pd.isna(short_liq_z):
short_liq_z = 0
if pd.isna(total_liq_z):
total_liq_z = 0
if pd.isna(oi_change):
oi_change = 0
if total_liq_z > 3:
return "RISK_OFF"
if funding_z > 2 and oi_change > 0:
return "LONG_CROWDED"
if funding_z < -2 and oi_change > 0:
return "SHORT_CROWDED"
if short_liq_z > 2 and funding_z < 0:
return "SHORT_SQUEEZE"
if long_liq_z > 2 and funding_z > 0:
return "LONG_SQUEEZE"
return "NEUTRAL"
Signal meanings:
| Signal | Meaning |
|---|---|
| NEUTRAL | Market structure is normal |
| LONG_CROWDED | Long side may be overcrowded |
| SHORT_CROWDED | Short side may be overcrowded |
| SHORT_SQUEEZE | Shorts may be getting forced out |
| LONG_SQUEEZE | Longs may be getting forced out |
| RISK_OFF | Extreme liquidation environment |
This is the core logic of a derivatives-aware bot.
15. Combine Price Signal and Derivatives Signal
Now combine the basic price signal with the CoinGlass-driven market state.
def final_trading_decision(price_signal, derivatives_state):
"""
Combine price signal with derivatives market state.
"""
if derivatives_state == "RISK_OFF":
return "HOLD"
if price_signal == "BUY" and derivatives_state == "LONG_CROWDED":
return "HOLD"
if price_signal == "SELL" and derivatives_state == "SHORT_CROWDED":
return "HOLD"
if price_signal == "BUY" and derivatives_state == "SHORT_SQUEEZE":
return "BUY"
if price_signal == "SELL" and derivatives_state == "LONG_SQUEEZE":
return "SELL"
if derivatives_state in ["NEUTRAL", "SHORT_SQUEEZE", "LONG_SQUEEZE"]:
return price_signal
return "HOLD"
Examples:
| Price Signal | Derivatives State | Final Decision |
|---|---|---|
| BUY | NEUTRAL | BUY |
| BUY | LONG_CROWDED | HOLD |
| SELL | SHORT_CROWDED | HOLD |
| BUY | SHORT_SQUEEZE | BUY |
| SELL | LONG_SQUEEZE | SELL |
| BUY | RISK_OFF | HOLD |
| SELL | RISK_OFF | HOLD |
This logic helps the bot avoid bad trades.
It does not guarantee profit, but it can reduce the likelihood of chasing crowded or unstable market conditions.
16. Add Position Sizing
A trading bot should not only decide whether to trade. It should also decide how much to trade.
def position_size_multiplier(derivatives_state):
multipliers = {
"NEUTRAL": 1.0,
"SHORT_SQUEEZE": 1.0,
"LONG_SQUEEZE": 1.0,
"LONG_CROWDED": 0.4,
"SHORT_CROWDED": 0.4,
"RISK_OFF": 0.0
}
return multipliers.get(derivatives_state, 0.5)
Example:
base_position_size = 1000 # USDT notional
derivatives_state = "LONG_CROWDED"
final_size = base_position_size * position_size_multiplier(derivatives_state)
print(final_size)
If the market is neutral, the bot may use normal size.
If the market is crowded, it may reduce size.
If the market is in risk-off mode, it does not trade.
This is often more useful than simply changing buy/sell signals.
17. Full Bot Framework Example
Below is a simplified full example.
It does not place real orders. Instead, it outputs a final trading decision. This is safer for demonstration and easier to adapt.
import os
import time
import requests
import pandas as pd
from dotenv import load_dotenv
load_dotenv()
BASE_URL = "https://open-api-v4.coinglass.com"
API_KEY = os.getenv("COINGLASS_API_KEY")
if not API_KEY:
raise RuntimeError("Missing COINGLASS_API_KEY environment variable")
HEADERS = {
"CG-API-KEY": API_KEY,
"Accept": "application/json"
}
def request_coinglass(endpoint, params=None):
url = f"{BASE_URL}{endpoint}"
response = requests.get(
url,
headers=HEADERS,
params=params,
timeout=10
)
response.raise_for_status()
return response.json()
def safe_request_coinglass(endpoint, params=None, retries=3, sleep_seconds=2):
last_error = None
for attempt in range(retries):
try:
return request_coinglass(endpoint, params)
except requests.RequestException as error:
last_error = error
print(f"Request failed: attempt {attempt + 1}/{retries}: {error}")
time.sleep(sleep_seconds)
raise last_error
def to_dataframe(raw):
data = raw.get("data", [])
if isinstance(data, dict):
rows = data.get("list", [])
else:
rows = data
df = pd.DataFrame(rows)
if df.empty:
return df
if "time" in df.columns:
df["time"] = pd.to_datetime(df["time"], unit="ms", errors="coerce")
return df
def zscore(series, window=24):
mean = series.rolling(window).mean()
std = series.rolling(window).std()
return (series - mean) / std
def fetch_open_interest(symbol="BTC", interval="1h", limit=100):
endpoint = "/api/futures/openInterest/ohlc-history"
params = {
"symbol": symbol,
"interval": interval,
"limit": limit
}
return safe_request_coinglass(endpoint, params)
def fetch_funding_rate(symbol="BTC", interval="1h", limit=100):
endpoint = "/api/futures/fundingRate/oi-weight-ohlc-history"
params = {
"symbol": symbol,
"interval": interval,
"limit": limit
}
return safe_request_coinglass(endpoint, params)
def fetch_liquidation_history(
symbol="BTC",
exchanges="Binance,OKX,Bybit",
interval="1h",
limit=100
):
endpoint = "/api/futures/liquidation/aggregated-history"
params = {
"exchange_list": exchanges,
"symbol": symbol,
"interval": interval,
"limit": limit
}
return safe_request_coinglass(endpoint, params)
def add_open_interest_features(df):
data = df.copy()
if "close" in data.columns:
data["oi_close"] = pd.to_numeric(data["close"], errors="coerce")
elif "openInterest" in data.columns:
data["oi_close"] = pd.to_numeric(data["openInterest"], errors="coerce")
else:
raise ValueError("No recognizable open interest field found")
data["oi_change"] = data["oi_close"].pct_change()
data["oi_change_24"] = data["oi_close"].pct_change(24)
return data
def add_funding_features(df, window=24):
data = df.copy()
if "close" in data.columns:
data["funding_close"] = pd.to_numeric(data["close"], errors="coerce")
elif "fundingRate" in data.columns:
data["funding_close"] = pd.to_numeric(
data["fundingRate"],
errors="coerce"
)
else:
raise ValueError("No recognizable funding rate field found")
data["funding_z"] = zscore(data["funding_close"], window)
return data
def add_liquidation_features(df, window=24):
data = df.copy()
data = data.rename(columns={
"longLiquidation": "long_liquidation",
"shortLiquidation": "short_liquidation",
"long_liq": "long_liquidation",
"short_liq": "short_liquidation"
})
if "long_liquidation" not in data.columns:
raise ValueError("No long liquidation field found")
if "short_liquidation" not in data.columns:
raise ValueError("No short liquidation field found")
data["long_liquidation"] = pd.to_numeric(
data["long_liquidation"],
errors="coerce"
)
data["short_liquidation"] = pd.to_numeric(
data["short_liquidation"],
errors="coerce"
)
data["long_liq_z"] = zscore(data["long_liquidation"], window)
data["short_liq_z"] = zscore(data["short_liquidation"], window)
data["total_liquidation"] = (
data["long_liquidation"] + data["short_liquidation"]
)
data["total_liq_z"] = zscore(data["total_liquidation"], window)
return data
def prepare_time_column(df):
data = df.copy()
if "time" not in data.columns:
raise ValueError("Missing time column")
data = data.dropna(subset=["time"])
data = data.sort_values("time")
return data
def merge_market_data(oi_df, funding_df, liquidation_df):
oi = prepare_time_column(oi_df)
funding = prepare_time_column(funding_df)
liquidation = prepare_time_column(liquidation_df)
merged = pd.merge_asof(
oi,
funding,
on="time",
direction="nearest",
tolerance=pd.Timedelta("10min"),
suffixes=("_oi", "_funding")
)
merged = pd.merge_asof(
merged,
liquidation,
on="time",
direction="nearest",
tolerance=pd.Timedelta("10min")
)
return merged
def classify_derivatives_state(row):
funding_z = row.get("funding_z", 0)
long_liq_z = row.get("long_liq_z", 0)
short_liq_z = row.get("short_liq_z", 0)
total_liq_z = row.get("total_liq_z", 0)
oi_change = row.get("oi_change", 0)
values = [funding_z, long_liq_z, short_liq_z, total_liq_z, oi_change]
values = [0 if pd.isna(v) else v for v in values]
funding_z, long_liq_z, short_liq_z, total_liq_z, oi_change = values
if total_liq_z > 3:
return "RISK_OFF"
if funding_z > 2 and oi_change > 0:
return "LONG_CROWDED"
if funding_z < -2 and oi_change > 0:
return "SHORT_CROWDED"
if short_liq_z > 2 and funding_z < 0:
return "SHORT_SQUEEZE"
if long_liq_z > 2 and funding_z > 0:
return "LONG_SQUEEZE"
return "NEUTRAL"
def final_trading_decision(price_signal, derivatives_state):
if derivatives_state == "RISK_OFF":
return "HOLD"
if price_signal == "BUY" and derivatives_state == "LONG_CROWDED":
return "HOLD"
if price_signal == "SELL" and derivatives_state == "SHORT_CROWDED":
return "HOLD"
if price_signal == "BUY" and derivatives_state == "SHORT_SQUEEZE":
return "BUY"
if price_signal == "SELL" and derivatives_state == "LONG_SQUEEZE":
return "SELL"
if derivatives_state in ["NEUTRAL", "SHORT_SQUEEZE", "LONG_SQUEEZE"]:
return price_signal
return "HOLD"
def position_size_multiplier(derivatives_state):
multipliers = {
"NEUTRAL": 1.0,
"SHORT_SQUEEZE": 1.0,
"LONG_SQUEEZE": 1.0,
"LONG_CROWDED": 0.4,
"SHORT_CROWDED": 0.4,
"RISK_OFF": 0.0
}
return multipliers.get(derivatives_state, 0.5)
def run_bot_once(symbol="BTC"):
oi_raw = fetch_open_interest(symbol=symbol, interval="1h", limit=100)
funding_raw = fetch_funding_rate(symbol=symbol, interval="1h", limit=100)
liquidation_raw = fetch_liquidation_history(
symbol=symbol,
interval="1h",
limit=100
)
oi_df = add_open_interest_features(to_dataframe(oi_raw))
funding_df = add_funding_features(to_dataframe(funding_raw))
liquidation_df = add_liquidation_features(to_dataframe(liquidation_raw))
market_df = merge_market_data(oi_df, funding_df, liquidation_df)
if market_df.empty:
raise ValueError("Merged market data is empty")
latest = market_df.iloc[-1]
# Example only. Replace this with your real price signal.
price_signal = "BUY"
derivatives_state = classify_derivatives_state(latest)
final_decision = final_trading_decision(price_signal, derivatives_state)
base_position_size = 1000
multiplier = position_size_multiplier(derivatives_state)
final_position_size = base_position_size * multiplier
result = {
"symbol": symbol,
"time": latest["time"],
"price_signal": price_signal,
"derivatives_state": derivatives_state,
"final_decision": final_decision,
"position_size": final_position_size
}
return result
if __name__ == "__main__":
result = run_bot_once("BTC")
print("Bot result:")
for key, value in result.items():
print(f"{key}: {value}")
This bot framework does not place orders. That is intentional.
Before connecting any strategy to real trading, you should:
- Backtest it
- Paper trade it
- Add exchange execution logic
- Add risk limits
- Add error handling
- Add logs
- Add monitoring
- Start with small position size
18. How to Add Exchange Execution
Once the CoinGlass API side works, you can connect the decision output to an exchange API.
The execution layer should be separate from the signal layer.
Example structure:
def execute_trade(decision, symbol, position_size):
"""
Placeholder execution function.
Replace with your exchange API logic.
"""
if decision == "BUY":
print(f"Place BUY order for {symbol}, size={position_size}")
elif decision == "SELL":
print(f"Place SELL order for {symbol}, size={position_size}")
else:
print(f"No trade for {symbol}")
Then:
result = run_bot_once("BTC")
execute_trade(
decision=result["final_decision"],
symbol=result["symbol"],
position_size=result["position_size"]
)
In production, the execution function should handle:
- Order type
- Quantity precision
- Minimum notional
- Slippage
- Leverage
- Margin mode
- Reduce-only orders
- Stop loss
- Take profit
- Position checking
- Order status confirmation
Never connect a strategy directly to live execution without safety checks.
19. Risk Management Rules
A trading bot without risk management is not a trading system. It is just an automated order sender.
At minimum, your bot should include:
| Rule | Purpose |
|---|---|
| Max position size | Prevent oversized trades |
| Max daily loss | Stop trading after major losses |
| Max open positions | Avoid overexposure |
| Stop loss | Limit downside |
| Take profit | Lock gains |
| Cooldown period | Avoid overtrading |
| Risk-off mode | Stop trading during extreme events |
| API failure mode | Avoid trading with stale data |
Example risk filter:
def risk_filter(account_state, market_state):
"""
Example risk control logic.
"""
if account_state["daily_loss_pct"] < -3:
return "STOP_TRADING"
if account_state["open_positions"] >= account_state["max_positions"]:
return "NO_NEW_POSITIONS"
if market_state["derivatives_state"] == "RISK_OFF":
return "NO_NEW_POSITIONS"
return "ALLOW"
Risk management should override signal generation.
A good rule is:
Signal decides what you want to do.
Risk decides whether you are allowed to do it.
20. Backtesting the Strategy
Before using real money, backtest the bot.
A proper backtest should include:
- Price candles
- Open interest history
- Funding rate history
- Liquidation history
- Trading fees
- Slippage
- Funding payments
- Latency assumptions
- Position size rules
- Stop loss logic
- Market regime changes
A basic backtest loop may look like this:
def backtest(market_df, price_signals):
equity = 10000
position = 0
trades = []
for i in range(len(market_df)):
row = market_df.iloc[i]
price_signal = price_signals[i]
derivatives_state = classify_derivatives_state(row)
decision = final_trading_decision(price_signal, derivatives_state)
size_multiplier = position_size_multiplier(derivatives_state)
trades.append({
"time": row["time"],
"price_signal": price_signal,
"derivatives_state": derivatives_state,
"decision": decision,
"size_multiplier": size_multiplier
})
return pd.DataFrame(trades)
This is only a skeleton. A real backtest must calculate:
- Entry price
- Exit price
- PnL
- Fees
- Funding payments
- Drawdown
- Sharpe ratio
- Win rate
- Average profit/loss
- Maximum loss
- Exposure time
Do not skip this step.
A strategy that looks good in a single example may fail across different market regimes.
21. Production Checklist
Before putting a CoinGlass API-powered trading bot into production, use this checklist.
| Checklist Item | Why It Matters |
|---|---|
| Confirm latest API endpoints | API routes and parameters may change |
| Confirm response fields | Field names may differ by endpoint |
| Store API key securely | Prevent credential leaks |
| Add request retries | Handle temporary errors |
| Add timeout handling | Prevent stuck processes |
| Add data validation | Avoid trading on broken data |
| Add stale data checks | Avoid using old signals |
| Add rate limit handling | Prevent API blocking |
| Add logs | Debug strategy behavior |
| Add paper trading | Validate real-time behavior |
| Add risk limits | Prevent catastrophic loss |
| Add monitoring alerts | Detect failures quickly |
| Add manual shutdown | Stop bot during emergencies |
| Start small | Reduce deployment risk |
Example stale data check:
def check_data_freshness(latest_time, max_age_minutes=90):
now = pd.Timestamp.utcnow()
if latest_time.tzinfo is None:
latest_time = latest_time.tz_localize("UTC")
age = now - latest_time
if age > pd.Timedelta(minutes=max_age_minutes):
raise ValueError(f"Data is stale: latest data age is {age}")
return True
22. Common Mistakes
Mistake 1: Using Funding Rate as a Standalone Signal
Funding rate should not be used alone.
Wrong:
Funding high → short
Funding low → long
Better:
Funding high → long side may be crowded
Funding low → short side may be crowded
Confirm with OI, price, and liquidation data
Mistake 2: Entering Immediately After Liquidations
A liquidation spike can mean a reversal, but it can also mean trend continuation.
You need to check:
- Did price reclaim the level?
- Did open interest drop?
- Did funding normalize?
- Did volume fade?
- Did the liquidation cascade continue?
Mistake 3: Ignoring Open Interest
Price without OI context can be misleading.
| Price Move | OI Move | Possible Meaning |
|---|---|---|
| Up | Up | New longs or new positions support the move |
| Up | Down | Shorts closing |
| Down | Up | New shorts entering |
| Down | Down | Longs closing or liquidating |
Mistake 4: Overfitting Too Many Indicators
Start simple.
A practical first version can use:
Price signal
+ OI confirmation
+ Funding filter
+ Liquidation risk filter
+ Position sizing rule
Then test improvements one by one.
Mistake 5: No Kill Switch
Every live bot needs a manual and automatic kill switch.
Examples:
Stop trading if API data is stale.
Stop trading if daily loss exceeds threshold.
Stop trading if liquidation risk is extreme.
Stop trading if exchange order API behaves unexpectedly.
23. Strategy Templates You Can Build with CoinGlass API
Template 1: Trend Confirmation Bot
Goal:
Trade only when price trend is supported by derivatives data.
Rules:
| Condition | Requirement |
|---|---|
| Price | Breakout or moving average trend |
| Open Interest | Rising gradually |
| Funding Rate | Not extreme |
| Liquidations | No abnormal opposite-side risk |
| Decision | Allow trade |
Best for:
- BTC trend strategies
- ETH momentum strategies
- Multi-asset futures bots
Template 2: Short Squeeze Bot
Goal:
Detect possible short squeeze setups.
Rules:
| Condition | Requirement |
|---|---|
| Funding Rate | Negative |
| Open Interest | High or rising |
| Price | Breaks resistance |
| Short Liquidations | Rising |
| Decision | Allow long signal |
Best for:
- Breakout bots
- Momentum bots
- Event-driven strategies
Template 3: Long Squeeze Risk Filter
Goal:
Avoid long exposure when the long side is overcrowded.
Rules:
| Condition | Requirement |
|---|---|
| Funding Rate | Very positive |
| Open Interest | Rising |
| Price | Breaks support |
| Long Liquidations | Rising |
| Decision | Exit, reduce, or avoid longs |
Best for:
- Grid bots
- Long-biased bots
- Leveraged futures strategies
Template 4: Funding Rate Arbitrage Monitor
Goal:
Detect cross-exchange funding rate opportunities.
Rules:
| Condition | Requirement |
|---|---|
| Funding difference | Large enough |
| Liquidity | Sufficient |
| Open Interest | Stable |
| Liquidation risk | Not extreme |
| Decision | Alert or evaluate trade |
Best for:
- Market-neutral strategies
- Funding capture bots
- Arbitrage dashboards
Template 5: Risk-Off Detector
Goal:
Pause trading during extreme derivatives stress.
Rules:
| Condition | Trigger |
|---|---|
| Total liquidation z-score | Above 3 |
| Funding z-score | Extreme |
| OI change | Abnormal |
| Price volatility | High |
| Decision | Pause trading |
Best for:
- All leveraged bots
- Portfolio risk systems
- Multi-strategy trading platforms
24. How to Expand the Bot
After building the first version, you can expand it with more CoinGlass API data.
Add Long/Short Ratio
Use long/short ratio to detect market sentiment imbalance.
Possible rule:
If long/short ratio is extremely long
AND funding is positive
AND OI is rising
THEN reduce long exposure.
Add Taker Buy/Sell Volume
Use taker buy/sell volume to confirm aggressive flow.
Possible rule:
If price breaks resistance
AND taker buy volume rises
AND short liquidations rise
THEN confirm short squeeze.
Add Liquidation Heatmap
Use liquidation heatmap data to identify zones where forced liquidations may occur.
Possible rule:
If price approaches large liquidation cluster
THEN reduce leverage or tighten stop.
Add Order Book Data
Use order book data for execution quality.
Possible rule:
If order book depth is thin
THEN reduce order size or use limit orders.
Add ETF Flow Data
For BTC and ETH, ETF flow data can help detect broader market demand.
Possible rule:
If ETF inflows are strong
AND derivatives data is not overheated
THEN increase bullish confidence.
25. Final Thoughts
Building a crypto trading bot is not just about coding buy and sell rules.
A strong bot needs to understand market conditions.
Price tells you what happened.
Derivatives data helps explain why it happened.
CoinGlass API can help trading bots move from simple price-based automation to a more complete market-aware system by providing data such as:
- Open interest
- Funding rate
- Liquidations
- Long/short ratio
- Taker buy/sell volume
- Order book data
- Liquidation heatmap
- ETF flow data
- Options data
A basic bot might say:
Price is above the moving average, so buy.
A better bot says:
Price is above the moving average.
Open interest is rising.
Funding rate is neutral.
Liquidations are normal.
Market structure is healthy.
Buy signal is allowed.
Or:
Price is above the moving average.
But funding is extremely positive.
Open interest is rising too fast.
Long side is crowded.
Do not chase.
That is the difference between a simple script and a more intelligent trading system.
No API can guarantee profitable trading. CoinGlass API does not replace strategy design, risk management, execution quality, or backtesting.
But it can provide the derivatives market intelligence that many trading bots are missing.
If you are building a crypto futures or perpetual trading bot, CoinGlass API is one of the most practical ways to add market structure awareness to your system.
Top comments (0)