Весь 2025-й я ковырялся в pair trading стратегиях, бэктестил их вдоль и поперек. И — не нашёл там эджа.
Пробовал классические подходы:
— линейная регрессия двух активов (акций или криптовалют) со скользящим окном
— вход и выход в спрэд через боллинджера
— моделирование спрэда с помощью OU-процесса (процесса Орнштейна-Уленбека)
— сглаживание коэффициентов регрессии с помощью фильтра Калмана
— использование не одной пары активов, а портфеля пар
Но ничто из этого не дало мне стабильно выигрышного алгоритма. Объясняю это тем, что:
— классический pair trading на двух активах давно и хорошо известен, и из него арбитраж уже высосан
— коинтеграция пары активов нестабильна и быстро разваливается
О потраченном времени не жалею: много чего узнал, особенно из области статистики, разобрал несколько интересных фундаментальных статей на эту тему, например Avellaneda, Lee — Statistical Arbitrage in the U.S. Equities Market (
papers.ssrn.com/sol3/papers.cfm?abstract_id=1153505 ).
Считаю, что сама идея статистического арбитража не тупиковая, она жива и используется во многих хедж-фондах, но ее нужно прокачивать с помощью:
— кросс-секционной корреляции между активами
— PCA-анализа
— детектирования режима
— и т.д.
В классическом pair trading в его ютубном варианте (пара активов → регрессия → боллинджер → профит)
эджа не осталось, а если кто-то скажет, что зарабатывает на нём — не поверю.
Я продолжу ковыряться в арбитраже — мне очень интересна эта область, но пока, чтобы перезагрузиться, решил попробовать какие-нибудь простейшие тренд-стратегии.
Пробэктестил сегодня такие классические тренд-стратегии на биткоине:
1) сигнал «пересекающиеся скользящие средние»
2) сигнал «знак доходностей актива по нескольким горизонтам», т.е.
Первый вариант оказался так себе, а вот второй интересный!
Биткоин с лёгкостью побит. Метрики:
CAGR 65.1%
Sharpe 1.54
Max DD -48.7%
Вот питон-код. Long-only позиции. Дневные данные. Расходы/проскальзывания не учитываются:
df = pd.read_excel("/mnt/data/BTC_price.xlsx")
df = df.sort_values("TradingDate").reset_index(drop=True)
P = df["ClosePrice"]
# --- Daily close-to-close returns ---
df["r"] = P.pct_change() # r_t = P_t/P_{t-1} - 1
# --- Horizon returns ---
L1, L2 = 10, 30
df["R_10"] = P / P.shift(L1) - 1 # R_{t,10}
df["R_30"] = P / P.shift(L2) - 1 # R_{t,30}
# --- Signal and position (long/flat) ---
# S_t = sign(R_{t,10} + R_{t,30})
df["S"] = np.sign(df["R_10"] + df["R_30"])
# pos_t = 1{ S_{t-1} > 0 } (trade next day)
df["pos"] = (df["S"] > 0).shift(1).astype(float)
# --- Strategy returns ---
df["r_strat"] = df["pos"] * df["r"]
# --- Drop rows with NaNs from shifts/pct_change ---
bt = df.dropna().copy()
# --- Equity curves ---
bt["equity_strat"] = (1 + bt["r_strat"]).cumprod()
bt["equity_btc"] = (1 + bt["r"]).cumprod()
Очень интересно, что такая простая идея привела к уже неплохому результату. Поковыряюсь-ка я в классических ссылках по трендовым алгоритмам, посмотрю, какие там еще есть подходы. Вот одна из фундаментальных статей:
www.sciencedirect.com/science/article/pii/S0304405X11002613
Большой Брат, конечно, прямо в таком виде я торговать бы не стал, но интересно покрутить и попробовать улучшить. Вот где был реализован этот drawdown. Биткоин тогда упал на 77%.
Большой Брат, у стратегий следования за трендом высокая макс. просадка и низкий коэффициент Шарпа. Проблема остальных стратегий в том, что даже если на истории макс. просадка низкая, то не факт что высокой не будет в будущем. Так же при увеличении ожидаемой дохдности растут и риски обычно
+ я молчу что у биткоина просадки бывают по 80-90%
Ну, и просадка 80% на самом деле не с одного трейда, а с серии. А с серией убытков можно по пути что-то делать.
Хотите тренда? А готовы как, к примеру, в 2025м 9 месяцев выживать около нуля? И дотяните ли вы до тех трех месяцев которые сделают годовую прибыль?