#!/usr/bin/env python3 """ ДЕЛЬТА-НЕЙТРАЛЬНЫЙ ГРИД — честная модель со ВСЕМИ издержками. Простой грид неявно длинный: в падающем рынке копит инвентарь и тонет. За 90 дней SOL −14%, BTC −17%, ETH −20% — поэтому нехеджированный грид показывал минус, хотя РЕАЛИЗОВАННЫЙ доход был +19…+41% годовых. Идея: держать инвентарь захеджированным шортом перпетуала. Тогда остаётся реализованный грид-доход + фандинг, без направленного риска. Что модель считает ЧЕСТНО (в отличие от наивного бэктеста): 1. КАПИТАЛ = полный резерв сетки (все уровни), а не пиковое использование + маржа под хедж. Нельзя запускать грид на 20 уровней, имея деньги на 5. 2. ХЕДЖ-ИЗДЕРЖКИ: каждое изменение инвентаря = ребаланс шорта = тейкер-комиссия 3. ФАНДИНГ по факту (историческая ставка, шорт получает при положительной) 4. КОНСЕРВАТИВНЫЕ ФИЛЛЫ: касание фитилём не всегда исполняет весь объём → коэффициент исполнения fill_ratio Запуск: python3 neutral_grid.py SOLUSDT --step 1.6 python3 neutral_grid.py all """ import sys, os, json, urllib.request, statistics sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) from grid_sim import load SPOT_FEE = 0.00075 # 0.075% спот с BNB PERP_FEE = 0.00045 # 0.045% тейкер на перпетуале (ребаланс хеджа) FILL_RATIO = 0.80 # только 80% касаний считаем исполненными (консервативно) UNIT = 100.0 FUNDING_APR = {"SOLUSDT": -0.8, "BTCUSDT": +3.4, "ETHUSDT": +2.3} # % годовых для ШОРТА def simulate_neutral(candles, step_pct, n_levels, unit=UNIT): step = step_pct / 100.0 center = candles[0][4] levels = [center * (1 - step * (i + 1)) for i in range(n_levels)] open_pos = {} realized = 0.0 hedge_cost = 0.0 fills = 0 rebalances = 0 peak_inv = 0.0 for ts, o, h, l, c in candles: for i, lvl in enumerate(levels): if i in open_pos or l > lvl: continue open_pos[i] = lvl # хедж: открыли лонг спот → добавили шорт перп hedge_cost += unit * PERP_FEE rebalances += 1 for i in list(open_pos.keys()): entry = open_pos[i] if h >= entry * (1 + step): gross = unit * step spot_fees = unit * SPOT_FEE + unit * (1 + step) * SPOT_FEE realized += gross - spot_fees fills += 1 # хедж: закрыли лонг → сняли шорт hedge_cost += unit * PERP_FEE rebalances += 1 del open_pos[i] peak_inv = max(peak_inv, len(open_pos) * unit) days = (candles[-1][0] - candles[0][0]) / 86400000 # консервативная поправка на исполнение realized *= FILL_RATIO hedge_cost *= FILL_RATIO fills = int(fills * FILL_RATIO) # КАПИТАЛ: полный резерв сетки + маржа под хедж (считаем 1:1, без плеча) grid_capital = n_levels * unit hedge_margin = peak_inv # шорт на размер инвентаря capital = grid_capital + hedge_margin net = realized - hedge_cost apr_grid = net / capital * 100 * (365 / days) return { "fills": fills, "realized": realized, "hedge_cost": hedge_cost, "net": net, "capital": capital, "grid_capital": grid_capital, "peak_inv": peak_inv, "days": days, "apr": apr_grid, "rebalances": int(rebalances * FILL_RATIO), "fee_share": (hedge_cost / (realized + hedge_cost) * 100) if realized + hedge_cost else 0, } def report(sym, steps=(0.5, 0.8, 1.0, 1.2, 1.6, 2.0, 2.5, 3.0), n_levels=20): candles = load(sym) fund_apr = FUNDING_APR.get(sym, 0) print(f"\n{'='*100}") print(f"{sym} · 90 дней · цена {(candles[-1][4]/candles[0][4]-1)*100:+.1f}% · " f"фандинг для шорта {fund_apr:+.1f}% годовых") print(f"{'='*100}") print(f"{'шаг':>6} {'филлы':>7} {'реализ$':>9} {'хедж$':>8} {'нетто$':>9} " f"{'капитал$':>10} {'APR грид':>9} {'+фандинг':>9} {'ИТОГО APR':>10}") print("-" * 100) out = [] for s in steps: r = simulate_neutral(candles, s, n_levels) fund_contrib = fund_apr * (r["peak_inv"] / r["capital"]) total_apr = r["apr"] + fund_contrib out.append((total_apr, s, r)) print(f"{s:>5}% {r['fills']:>7} {r['realized']:>9,.0f} {r['hedge_cost']:>8,.0f} " f"{r['net']:>9,.0f} {r['capital']:>10,.0f} {r['apr']:>8.1f}% " f"{fund_contrib:>+8.1f}% {total_apr:>9.1f}%") out.sort(reverse=True) best = out[0] print(f"\nЛУЧШИЙ: шаг {best[1]}% → {best[0]:.1f}% годовых на ${best[2]['capital']:,.0f} капитала") print(f" доля комиссий хеджа в обороте: {best[2]['fee_share']:.0f}%") print(f" ребалансов хеджа за 90 дней : {best[2]['rebalances']:,}") return best if __name__ == "__main__": print("ДЕЛЬТА-НЕЙТРАЛЬНЫЙ ГРИД — модель со всеми издержками") print(f"допущения: спот-комиссия {SPOT_FEE*100}% · перп-тейкер {PERP_FEE*100}% · " f"исполнение {FILL_RATIO*100:.0f}% касаний · без плеча") syms = ["SOLUSDT", "BTCUSDT", "ETHUSDT"] if (len(sys.argv) < 2 or sys.argv[1] == "all") else [sys.argv[1]] results = [] for s in syms: results.append((s, report(s))) if len(results) > 1: print(f"\n{'='*100}\nСВОДКА") for sym, (apr, step, r) in results: print(f" {sym:9} шаг {step:>4}% → {apr:>6.1f}% годовых, капитал ${r['capital']:,.0f}") print(f"\n средний APR портфеля из трёх: " f"{statistics.mean(a for _, (a, _, _) in results):.1f}%")