Разработка системы бэктестинга с учётом funding rate
Funding rate — периодический платёж между лонгами и шортами на perpetual futures рынках. Его игнорирование в бэктесте может существенно исказить результаты: при постоянно положительном funding (бычий рынок) лонговые стратегии переплачивают, при отрицательном — получают доход.
Механика funding rate
На большинстве perpetual futures бирж (Binance, Bybit, OKX) funding выплачивается каждые 8 часов в 00:00, 08:00, 16:00 UTC.
Формула:
Funding Payment = Position Value × Funding Rate
Если Funding Rate > 0: лонги платят шортам
Если Funding Rate < 0: шорты платят лонгам
Funding rate обычно находится в диапазоне -0.3% до +0.3% за 8 часов, но в периоды высокой волатильности может достигать 3–5%.
Загрузка исторических данных funding rate
import ccxt
import pandas as pd
class FundingRateLoader:
async def load_history(
self,
exchange_name: str,
symbol: str,
start_date: str,
end_date: str,
) -> pd.DataFrame:
exchange = getattr(ccxt, exchange_name)({'enableRateLimit': True})
all_rates = []
since = pd.Timestamp(start_date).timestamp() * 1000
while True:
rates = await exchange.fetch_funding_rate_history(
symbol=symbol,
since=int(since),
limit=500,
)
if not rates:
break
all_rates.extend(rates)
since = rates[-1]['timestamp'] + 1
if rates[-1]['timestamp'] > pd.Timestamp(end_date).timestamp() * 1000:
break
df = pd.DataFrame(all_rates)
df['datetime'] = pd.to_datetime(df['timestamp'], unit='ms', utc=True)
df = df.set_index('datetime')
return df[['fundingRate']]
Интеграция в бэктест движок
class FundingAwareBacktester:
FUNDING_INTERVAL_HOURS = 8
FUNDING_TIMES_UTC = [0, 8, 16] # часы UTC
def __init__(self, funding_data: pd.DataFrame, commission: float = 0.0005):
self.funding_data = funding_data
self.commission = commission
def calculate_funding_payments(
self,
position: Position,
from_timestamp: int,
to_timestamp: int,
) -> float:
"""Рассчитываем суммарный funding за период удержания позиции"""
from_dt = pd.Timestamp(from_timestamp, unit='ms', tz='UTC')
to_dt = pd.Timestamp(to_timestamp, unit='ms', tz='UTC')
# Находим все funding моменты внутри периода
funding_events = self.funding_data[
(self.funding_data.index > from_dt) &
(self.funding_data.index <= to_dt)
]
total_funding = 0.0
for ts, row in funding_events.iterrows():
rate = row['fundingRate']
position_value = abs(position.quantity) * position.current_price
if position.side == 'LONG':
# Лонги платят при положительном rate
payment = -position_value * rate
else:
# Шорты платят при отрицательном rate
payment = position_value * rate
total_funding += payment
return total_funding
def run_with_funding(self, strategy, ohlcv_data: pd.DataFrame) -> BacktestResult:
portfolio = Portfolio(initial_cash=100_000)
current_position = None
for i, (timestamp, row) in enumerate(ohlcv_data.iterrows()):
bar = Bar(timestamp=timestamp.value // 10**6, **row.to_dict())
# Применяем funding если есть открытая позиция
if current_position:
prev_ts = ohlcv_data.index[i-1].value // 10**6 if i > 0 else bar.timestamp
funding = self.calculate_funding_payments(
current_position, prev_ts, bar.timestamp
)
portfolio.cash += funding
current_position.funding_paid += -funding
# Стратегия
signal = strategy.on_bar(bar)
if signal:
current_position = self.execute_signal(portfolio, signal, bar)
return BacktestResult(portfolio)
Стратегии с funding rate как сигналом
Funding rate сам по себе является торговым сигналом:
class FundingRateStrategy:
"""
Funding Rate Arbitrage: при экстремальном funding
открываем противоположную направлению позицию.
При funding > 0.1% лонги переплачивают — значит рынок перегрет,
идём в шорт или держим нейтральную позицию.
"""
EXTREME_FUNDING_THRESHOLD = 0.001 # 0.1% за 8 часов
def on_bar(self, bar: Bar, current_funding_rate: float) -> Optional[Signal]:
if current_funding_rate > self.EXTREME_FUNDING_THRESHOLD:
# Экстремально позитивный funding: рынок бычий, много лонгов
# Открываем шорт или выходим из лонга
return Signal.SHORT
elif current_funding_rate < -self.EXTREME_FUNDING_THRESHOLD:
# Экстремально отрицательный: рынок медвежий
return Signal.LONG
return None
Влияние funding на P&L
Для стратегий удержания позиций несколько дней/недель funding существенен:
| Период | Среднее funding (8h) | Дневной cost | За 30 дней |
|---|---|---|---|
| Бычий рынок (2021) | +0.05–0.15% | +0.15–0.45% | +4.5–13.5% |
| Медвежий рынок (2022) | -0.01–0.05% | -0.03–0.15% | -0.9–4.5% |
| Боковик | ±0.01% | ±0.03% | ±0.9% |
В bull market лонговые стратегии теряли до 13% за месяц только на funding. Это существенно — его нельзя игнорировать в бэктесте фьючерсных стратегий.







