Размер позиции решает всё: Монте-Карло, где честно меняется ровно одна переменная
Дисклеймер о конфликте интересов.
Я делаю бесплатные калькуляторы риск-менеджмента для крипто-трейдинга. Чтобы это не выглядело как реклама в каждом абзаце, ссылка на проект в статье ровно одна — в самом конце. Всё остальное здесь — код, математика и числа, которые вы можете воспроизвести у себя за минуту.
И сразу к делу — с вопроса, на который у большинства есть «очевидный», но неверный ответ.
Вопрос
Два трейдера торгуют одну и ту же стратегию. Винрейт 55%, выплата 1:1 (выигрыш равен риску). Они получают буквально одну и ту же серию из 500 сделок — те же победы на тех же местах, те же поражения. Отличается только одно: первый рискует 10% депозита на сделку, второй — 35%.
У стратегии положительное матожидание. Второй рискует больше, значит и зарабатывать должен больше — так подсказывает интуиция.
Прогон 10 000 таких «карьер» на каждый размер ставки даёт:
-
ставка 10% → медианный итог $122 336 (старт был $10 000);
-
ставка 35% → медианный итог $0.006. Полцента.
Те же подбрасывания монеты. Отличается только размер ставки. Ниже — полный код, по которому это получено, таблица, графики и разбор, почему так.
Модель
Одна сделка меняет депозит на множитель:
-
выигрыш →
× (1 + f) -
проигрыш →
× (1 − f)
где f — риск на сделку: доля депозита, которую вы теряете на стопе. Это не номинал позиции и не плечо, а именно «сколько денег от счёта сгорает, если сделка против вас». Выплата симметричная (1:1), то есть выигрыш приносит ровно то же f, что отнимает проигрыш.
Параметры:
-
p = 0.55— доля выигрышных сделок, одинаковая для всех размеров ставки; -
START = $10 000— стартовый депозит; -
N_TRADES = 500— сделок в одной «карьере»; -
N_RUNS = 10 000— «карьер» на каждый размер ставки; -
RISKS = 1%, 2%, 5%, 10%, 20%, 35%— то, что мы перебираем; -
«слив» — депозит хотя бы раз опускался ниже 10% от старта.
Как обеспечена честность сравнения
Это главное, ради чего стоит читать дальше. Подогнать такую симуляцию — нечего делать: достаточно тайком занизить винрейт «плохой» стратегии или прогнать каждый размер ставки на своей серии случайностей. Поэтому конструкция построена так, чтобы подгонку было невозможно спрятать:
-
Меняется ровно одна переменная — размер ставки. Винрейт у всех одинаковый:
p = 0.55. -
Все размеры ставки прогоняются на ОДНОЙ И ТОЙ ЖЕ матрице исходов. Сначала генерируется матрица побед/поражений
10 000 × 500, и затем каждыйfприменяется к ней же. Сид зафиксирован (SEED = 7). -
Код опубликован целиком (ниже). Скопируйте, запустите — получите те же числа до цента.
-
Медиана из симуляции сверяется с аналитической формулой прямо в таблице. Если бы код врал, столбцы «медиана» и «теория» разошлись бы. Они совпадают.
-
Каждое число в статье — из реального прогона. Сначала прогон, потом текст. Ничего «по памяти» и ничего «по теории» под видом результата симуляции.
Код
Это и есть весь скрипт целиком — он печатает таблицу из следующего раздела. Сохраните его в файл habr_sim.py и запустите python3 habr_sim.py: таблица воспроизводится один в один.
import numpy as npSEED = 7START = 10_000 # стартовый депозит, $P_WIN = 0.55 # доля выигрышных сделок — одинаковая у всехN_TRADES = 500 # сделок в одной «карьере»N_RUNS = 10_000 # «карьер» на каждый размер ставкиRISKS = [0.01, 0.02, 0.05, 0.10, 0.20, 0.35] # риск на сделку, доля депозитаRUIN = 0.10 # «слив»: депозит хотя бы раз опускался ниже 10% от стартаrng = np.random.default_rng(SEED)# Честность конструкции: ОДНИ И ТЕ ЖЕ последовательности побед/поражений# для всех размеров ставки. Меняется ровно одна переменная — размер.wins = rng.random((N_RUNS, N_TRADES)) < P_WINk_med = round(P_WIN * N_TRADES) # медианное число побед: 275 из 500print(f"{'ставка':>7} | {'медиана, $':>14} | {'теория, $':>14} | " f"{'P(итог<старта)':>14} | {'P(слив)':>8} | {'P(DD>50%)':>9}")for f in RISKS: mult = np.where(wins, 1 + f, 1 - f) # множитель депозита за сделку paths = START * np.cumprod(mult, axis=1) # траектории депозита full = np.concatenate([np.full((N_RUNS, 1), START), paths], axis=1) drawdown = 1 - full / np.maximum.accumulate(full, axis=1) med = np.median(paths[:, -1]) theory = START * (1 + f)**k_med * (1 - f)**(N_TRADES - k_med) p_loss = (paths[:, -1] < START).mean() p_ruin = (full.min(axis=1) < START * RUIN).mean() p_dd = (drawdown.max(axis=1) > 0.50).mean() print(f"{f:>6.0%} | {med:>14,.2f} | {theory:>14,.2f} | " f"{p_loss:>13.1%} | {p_ruin:>7.1%} | {p_dd:>8.1%}")
Результаты
|
Ставка |
Медиана итога |
Теория (медианы) |
P(итог < старта) |
P(слив) |
P(DD > 50%) |
|---|---|---|---|---|---|
|
1% |
$16 080.39 |
$16 080.39 |
1.8% |
0.0% |
0.0% |
|
2% |
$24 598.82 |
$24 598.82 |
2.3% |
0.0% |
0.9% |
|
5% |
$65 293.27 |
$65 293.27 |
5.1% |
0.1% |
60.9% |
|
10% |
$122 335.65 |
$122 335.65 |
13.5% |
6.5% |
99.9% |
|
20% |
$9 334.47 |
$9 334.47 |
51.4% |
59.4% |
100.0% |
|
35% |
$0.01 * |
$0.01 * |
96.3% |
98.6% |
100.0% |
* При формате с двумя знаками после запятой значение для 35% округляется до $0.01; точная медиана ≈ $0.0056. Это видно на графике 1 и подтверждается формулой лог-роста ниже.
Два наблюдения, на которые стоит обратить внимание сразу.
Столбцы «медиана» и «теория» совпадают до цента во всех строках — и это не подгонка, а свойство задачи. Итоговый капитал зависит только от числа побед, а не от их порядка: умножение коммутативно, (1+f) и (1−f) можно переставлять как угодно. Поэтому итог однозначно определяется счётчиком побед k, а медианному итогу соответствует медианное число побед. Для Binomial(500, 0.55) медиана числа побед — ровно 275, и формула START · (1+f)²⁷⁵ · (1−f)²²⁵ бьёт с симуляцией один в один. Если бы в коде была ошибка в логике компаундинга, эти два столбца разъехались бы. Они не разъехались.
Столбцы «слив» и «DD > 50%» аналитически не считаются — их даёт только прогон. Они путезависимые: важно не только сколько побед, но и когда пришли поражения. Здесь и прячется главная ловушка крупной ставки: уже при 5% риска у 60.9% «карьер» хоть раз была просадка глубже 50% — при том что медианный итог отличный ($65k). При ставке Келли (10%) такую просадку переживают 99.9%, а 6.5% «карьер» хоть раз падали ниже 10% от старта.
График 1. Медиана растёт до ставки Келли (10%, $122k), а затем рушится: 20% даёт уже $9.3k (ниже старта), 35% — полцента. Положительное матожидание не спасает.
Почему так: критерий Келли и лог-рост
При мультипликативном компаундинге важна не арифметическая прибавка за сделку, а средний логарифмический рост:
g(f) = p · ln(1 + f) + q · ln(1 − f), где q = 1 − p
g(f) — это скорость, с которой растёт логарифм капитала за сделку. Медианный итог за N сделок ≈ START · e^(N · g(f)). Максимум g(f) достигается при ставке Келли; для выплаты 1:1 она равна:
f* = 2p − 1 = 2·0.55 − 1 = 0.10 → 10%
Подставляем реальные g(f) из прогона (та же формула, тот же p):
|
Ставка |
g(f) за сделку |
START · e^(500·g) |
|---|---|---|
|
1% |
+0.000950 |
$16 080 |
|
2% |
+0.001800 |
$24 599 |
|
5% |
+0.003753 |
$65 293 |
|
10% |
+0.005008 (максимум) |
$122 336 |
|
20% |
−0.000138 (≈ 0) |
$9 334 |
|
35% |
−0.028795 (< 0) |
$0.0056 |
Три зоны:
-
f < 10% —
g > 0, и чем ближе к Келли, тем быстрее растём. -
f = 20% (это 2× Келли) —
g ≈ 0. Рост логарифма капитала обнуляется: медиана возвращается примерно к старту. Удвоить ставку Келли — значит обнулить ожидаемый рост, а не удвоить прибыль. -
f = 35% —
g < 0. Матожидание положительное, но лог-рост отрицательный → медианное разорение. Капитал почти каждой отдельной «карьеры» съёживается до нуля, хотя «в среднем по больнице» (см. ниже) всё прекрасно.
Это и есть контринтуитивная суть: у функции g(f) есть пик, за которым больше риска = меньше денег, а дальше — гарантированный путь в ноль, несмотря на положительный матожидание каждой сделки.
График 2. Те же 60 серий побед/поражений, отличается только размер ставки. Слева (10%) траектории разлетаются вверх с большим разбросом, но большинство — выше старта. Справа (35%) тот же набор серий схлопывается ко дну ($0.01 — это пол визуализации, чтобы лог-шкала не уходила в −∞), редкие выжившие погоды не делают.
Среднее против медианы: откуда берётся иллюзия
Если посчитать не медиану, а среднее (арифметическое), картина переворачивается. Среднее добавляется к скрипту двумя строками на той же матрице:
terminal = paths[:, -1]mean_sample = terminal.mean() # выборочное среднееmean_theory = START * (1 + f * (2 * P_WIN - 1)) ** N_TRADES # теоретическое среднее
|
Ставка |
Медиана |
Среднее (выборка) |
Среднее (теория) |
|---|---|---|---|
|
1% |
$16 080 |
$16 472 |
$16 483 |
|
2% |
$24 599 |
$27 116 |
$27 156 |
|
5% |
$65 293 |
$120 326 |
$121 068 |
|
10% |
$122 336 |
$1 443 930 |
$1 447 728 |
|
20% |
$9 334 |
$111 697 574 |
$199 565 691 |
|
35% |
≈$0.006 |
$60 856 483 |
$295 239 795 928 |
При ставке 35% медиана — полцента, а теоретическое среднее — почти $295 млрд. Это не опечатка. Среднее тащат вверх единичные траектории, где почти все 500 сделок оказались выигрышными — астрономически богатые, но исчезающе редкие. Если ваша стратегия — «занести крупно и надеяться», математически вы ставите на то, что окажетесь именно на такой траектории. Почти наверняка — нет.
Честная оговорка про среднее. Обратите внимание: выборочное среднее при больших f систематически ниже теоретического (на 35%: $60.9 млн против $295 млрд). Это не ошибка кода. Основной вклад в теоретическое среднее дают редчайшие траектории, которых в 10 000 прогонов попросту нет — распределение итогов имеет чудовищно тяжёлый правый хвост. Поэтому столбец «среднее (выборка)» нужно читать как нижнюю оценку истинного среднего, а не как само среднее. Это честное свойство конечной выборки из распределения с экстремальным хвостом, и его важно проговаривать, а не прятать.
График 3. Чем выше ставка, тем чаще боль. Даже на «разумных» 5% риска у 60.9% «карьер» хоть раз случалась просадка глубже 50%. На 35% почти всё идёт не так одновременно.
А если вы ошиблись в оценке винрейта?
До сих пор мы считали, что p = 0.55 известно точно. В реальности винрейт — это оценка по конечной истории сделок, и она шумит.
Стандартное отклонение оценки винрейта по 500 сделкам:
σ = sqrt( p·(1−p) / n ) = sqrt( 0.55·0.45 / 500 ) ≈ 0.022 → 2.2 процентных пункта
То есть на дистанции в 500 сделок вы не можете статистически отличить винрейт 52% от 55% — они лежат внутри полутора сигм друг от друга. А разница для размера ставки — огромная:
-
Вы думаете, что
p = 0.55→ считаете Келлиf* = 10%. -
На самом деле
p = 0.52→ настоящий Келлиf* = 2·0.52 − 1 = 4%.
Что происходит, если ставить 10% при истинном p = 0.52:
g(10%) при p=0.52 = 0.52·ln(1.10) + 0.48·ln(0.90) = −0.001012 → g < 0START · e^(500·g) ≈ $6 030
g отрицательный — медиана падает ниже старта за 500 сделок. Вы были уверены, что играете по Келли с положительным ростом, а на деле медленно сливаетесь, потому что переоценили свой эдж на 3 пункта — на те самые 3 пункта, которые невозможно увидеть в данных.
Вывод не «Келли плохой», а ровно обратный по духу: поскольку истинный эдж измерить точно нельзя, ставить долю от Келли (дробный Келли) или учебные 1–2% риска — это не трусость и не «для слабаков». Это рациональное поведение под неопределённостью. Запас по размеру ставки — это плата за то, что вы не знаете свой винрейт с точностью до процента. И вы его действительно не знаете.
Честные оговорки
Это модель, а не реальность. Все упрощения перечислены явно — и почти все они в пользу трейдера, то есть реальность ещё суровее модели:
-
Винрейт фиксирован и известен. В жизни он неизвестен и плавает (что усугубляет проблему — см. раздел выше). Знать свой эдж идеально — это подарок, которого у вас нет.
-
Выплата ровно 1:1. Никакого разброса в R-мультипликаторах сделок.
-
Нет комиссий, проскальзывания, спреда и funding. Любые реальные издержки сдвигают всё только в худшую сторону.
-
Сделки независимы. Нет автокорреляции, смены режимов рынка, серий и тильта.
-
«Карьера» не останавливается на просадке. Симулированный трейдер не закрывает счёт после −80%, его не выносит по марже, у него нет эмоций. Реальные люди останавливаются — иногда спасая остаток, иногда фиксируя худшее в панике.
-
Все перечисленные упрощения играют ЗА трейдера — и всё равно переставка размера ставки разоряет его. На реальном рынке преимущество модели исчезает, а проблема остаётся.
-
Выборочное среднее при больших
fнедосэмплит теоретическое (см. оговорку про среднее) — это ограничение конечной выборки, а не свойство стратегии. -
Это не финансовый совет. Рынок — не подбрасывание монеты с известной вероятностью. Это иллюстрация одного конкретного механизма, не модель торговли.
Выводы
-
Размер позиции — не второстепенная ручка, а главная. При полностью зафиксированных винрейте, выплате и серии сделок именно размер ставки решает, компаундитесь вы или идёте в ноль.
-
Есть оптимум (Келли), за которым больше риска = меньше денег. А дальше — практически гарантированное разорение, несмотря на положительное матожидание каждой сделки.
-
Среднее ≠ медиана, когда доходности перемножаются. «Средняя» доходность — это иллюзия выжившего: её формируют траектории, на которых вас почти наверняка не будет.
-
Свой эдж точно измерить нельзя, поэтому дробный Келли и учебные 1–2% риска — это математически обоснованный ответ на неопределённость, а не робость.
-
Скучный, маленький размер позиции — это не отсутствие смелости. Это единственный размер, который защищён математикой.
Я делаю бесплатные калькуляторы риск-менеджмента для крипто-трейдинга, в том числе симулятор Монте-Карло вроде этого, но интерактивный — riskdesks.com. Это единственная ссылка в статье.
P.S. Код и сид открыты, симуляцию можно повторить за минуту. Если найдёте ошибку в построении, в математике или сможете показать, что честность сравнения где-то нарушена — напишите в комментариях, поправлю прямо в статье и укажу автора правки. Это ровно тот peer-review, ради которого пост и написан: ломайте методологию, а не верьте на слово.
ссылка на оригинал статьи https://habr.com/ru/articles/1047262/