Разработка индикатора Open Interest
Open Interest (OI) — это суммарное количество открытых позиций по фьючерсным контрактам. В отличие от объёма (который считает каждую сделку), OI показывает сколько позиций остаётся открытыми. Рост OI = новые деньги входят в рынок. Падение OI = позиции закрываются. Это один из немногих реально ведущих индикаторов.
Интерпретация Open Interest
| Цена | OI | Интерпретация |
|---|---|---|
| Растёт | Растёт | Сильный восходящий тренд (новые лонги открываются) |
| Растёт | Падает | Слабый рост (шорты закрываются, не новые лонги) |
| Падает | Растёт | Сильный нисходящий тренд (новые шорты) |
| Падает | Падает | Слабое падение (лонги закрываются, не новые шорты) |
Высокий OI + резкое движение = риск большого liquidation cascade. Именно так происходят самые жёсткие дампы: накопленные шорты или лонги ликвидируются цепной реакцией.
Получение данных OI
Binance Futures API
import httpx
from decimal import Decimal
import asyncio
class OpenInterestCollector:
BINANCE_FUTURES = "https://fapi.binance.com"
BYBIT_API = "https://api.bybit.com"
async def get_binance_oi(self, symbol: str) -> dict:
"""Текущий OI и исторические данные"""
async with httpx.AsyncClient() as client:
# Текущий OI
current = await client.get(
f"{self.BINANCE_FUTURES}/fapi/v1/openInterest",
params={"symbol": symbol}
)
current_data = current.json()
# Исторический OI (до 500 точек по 5-минутным интервалам)
history = await client.get(
f"{self.BINANCE_FUTURES}/futures/data/openInterestHist",
params={
"symbol": symbol,
"period": "5m",
"limit": 500
}
)
history_data = history.json()
return {
"current_oi": float(current_data["openInterest"]),
"current_oi_usd": float(current_data["openInterest"]) * self.get_price(symbol),
"history": [
{
"time": h["timestamp"],
"oi": float(h["sumOpenInterest"]),
"oi_usd": float(h["sumOpenInterestValue"])
}
for h in history_data
]
}
async def get_aggregated_oi(self, symbol: str) -> dict:
"""Агрегируем OI со всех бирж для единого взгляда"""
tasks = [
self.get_binance_oi(symbol),
self.get_bybit_oi(symbol),
self.get_okx_oi(symbol),
]
results = await asyncio.gather(*tasks, return_exceptions=True)
total_oi_usd = sum(
r.get("current_oi_usd", 0)
for r in results
if not isinstance(r, Exception)
)
return {
"total_oi_usd": total_oi_usd,
"by_exchange": {
"binance": results[0].get("current_oi_usd", 0) if not isinstance(results[0], Exception) else 0,
"bybit": results[1].get("current_oi_usd", 0) if not isinstance(results[1], Exception) else 0,
"okx": results[2].get("current_oi_usd", 0) if not isinstance(results[2], Exception) else 0,
}
}
OI Change Rate индикатор
Скорость изменения OI часто важнее абсолютного значения:
def calculate_oi_change_rate(oi_history: list[dict], window: int = 12) -> list[dict]:
"""
OI Change Rate: % изменение OI за последние N периодов.
Аномальный рост → потенциальный liquidation event.
"""
result = []
for i in range(window, len(oi_history)):
current_oi = oi_history[i]['oi_usd']
past_oi = oi_history[i - window]['oi_usd']
change_rate = (current_oi - past_oi) / past_oi * 100
# Флаг аномалии: изменение больше 2 стандартных отклонений
all_changes = [
(oi_history[j]['oi_usd'] - oi_history[j-window]['oi_usd']) / oi_history[j-window]['oi_usd'] * 100
for j in range(window, i+1)
]
mean_change = sum(all_changes) / len(all_changes)
std_change = (sum((x - mean_change)**2 for x in all_changes) / len(all_changes)) ** 0.5
z_score = (change_rate - mean_change) / std_change if std_change > 0 else 0
result.append({
'time': oi_history[i]['time'],
'oi': current_oi,
'change_rate': change_rate,
'z_score': z_score,
'is_anomaly': abs(z_score) > 2.0
})
return result
Liquidation Heatmap
Комбинирование OI с ценовыми уровнями позволяет строить liquidation heatmap — карту уровней, где сконцентрированы liquidation orders:
def estimate_liquidation_levels(
open_positions: list[dict], # данные о позициях (средний leverage, сторона)
current_price: float
) -> dict:
"""
Оцениваем ценовые уровни ликвидаций.
Источник данных: биржи иногда публикуют агрегированные данные об уровнях.
"""
long_liquidations = {}
short_liquidations = {}
for position in open_positions:
if position['side'] == 'long':
liq_price = position['avg_entry'] * (1 - 1/position['leverage'] + 0.005)
bucket = round(liq_price / 100) * 100 # группируем по $100
long_liquidations[bucket] = long_liquidations.get(bucket, 0) + position['size_usd']
else:
liq_price = position['avg_entry'] * (1 + 1/position['leverage'] - 0.005)
bucket = round(liq_price / 100) * 100
short_liquidations[bucket] = short_liquidations.get(bucket, 0) + position['size_usd']
return {
"long_liquidation_levels": long_liquidations, # ниже текущей цены
"short_liquidation_levels": short_liquidations, # выше текущей цены
"largest_long_liq": max(long_liquidations.items(), key=lambda x: x[1]) if long_liquidations else None,
"largest_short_liq": max(short_liquidations.items(), key=lambda x: x[1]) if short_liquidations else None
}
Коресиляция OI с ценой: практические паттерны
Long squeeze: OI высокий, преимущественно лонги → резкое падение цены → лонги ликвидируются → ещё больше падение. Признак: перед движением OI аномально высокий, Funding Rate положительный.
Short squeeze: противоположное. Много шортов, цена резко растёт, шорты ликвидируются — ракета вверх.
OI накопление в боковике: OI растёт при флэтовой цене → рынок накапливает позиции → будет движение (direction неизвестен заранее, но будет взрывное).
Мониторинг OI вместе с Funding Rate и ценой даёт значительно более полную картину рыночного состояния, чем только технический анализ. Профессиональные трейдеры используют эти данные как ключевые inputs при принятии решений.







