Размер позиции под микроскопом: Монте-Карло, где честно меняется ровно одна переменная

от автора

Размер позиции решает всё: Монте-Карло, где честно меняется ровно одна переменная

Дисклеймер о конфликте интересов.

Я делаю бесплатные калькуляторы риск-менеджмента для крипто-трейдинга. Чтобы это не выглядело как реклама в каждом абзаце, ссылка на проект в статье ровно одна — в самом конце. Всё остальное здесь — код, математика и числа, которые вы можете воспроизвести у себя за минуту.

И сразу к делу — с вопроса, на который у большинства есть «очевидный», но неверный ответ.

Вопрос

Два трейдера торгуют одну и ту же стратегию. Винрейт 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% от старта.

Как обеспечена честность сравнения

Это главное, ради чего стоит читать дальше. Подогнать такую симуляцию — нечего делать: достаточно тайком занизить винрейт «плохой» стратегии или прогнать каждый размер ставки на своей серии случайностей. Поэтому конструкция построена так, чтобы подгонку было невозможно спрятать:

  1. Меняется ровно одна переменная — размер ставки. Винрейт у всех одинаковый: p = 0.55.

  2. Все размеры ставки прогоняются на ОДНОЙ И ТОЙ ЖЕ матрице исходов. Сначала генерируется матрица побед/поражений 10 000 × 500, и затем каждый f применяется к ней же. Сид зафиксирован (SEED = 7).

  3. Код опубликован целиком (ниже). Скопируйте, запустите — получите те же числа до цента.

  4. Медиана из симуляции сверяется с аналитической формулой прямо в таблице. Если бы код врал, столбцы «медиана» и «теория» разошлись бы. Они совпадают.

  5. Каждое число в статье — из реального прогона. Сначала прогон, потом текст. Ничего «по памяти» и ничего «по теории» под видом результата симуляции.

Код

Это и есть весь скрипт целиком — он печатает таблицу из следующего раздела. Сохраните его в файл 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: медианный итог по размеру ставки. Лог-шкала Y, зелёные столбцы — выше старта, красные — ниже. Отмечен критерий Келли (10%) и пунктир старта $10 000. У 35% подпись ≈$0.0056.

График 1: медианный итог по размеру ставки. Лог-шкала Y, зелёные столбцы — выше старта, красные — ниже. Отмечен критерий Келли (10%) и пунктир старта $10 000. У 35% подпись ≈$0.0056.

График 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: две панели вееров траекторий, ставка 10% слева и 35% справа, на ОДНИХ И ТЕХ ЖЕ 60 последовательностях. Лог-шкала Y, пол на $0.01.

График 2: две панели вееров траекторий, ставка 10% слева и 35% справа, на ОДНИХ И ТЕХ ЖЕ 60 последовательностях. Лог-шкала Y, пол на $0.01.

График 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: сгруппированные столбцы по размеру ставки — доля «карьер», где итог ниже старта / была просадка >50% / случился слив.

График 3: сгруппированные столбцы по размеру ставки — доля «карьер», где итог ниже старта / была просадка >50% / случился слив.

График 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. Есть оптимум (Келли), за которым больше риска = меньше денег. А дальше — практически гарантированное разорение, несмотря на положительное матожидание каждой сделки.

  3. Среднее ≠ медиана, когда доходности перемножаются. «Средняя» доходность — это иллюзия выжившего: её формируют траектории, на которых вас почти наверняка не будет.

  4. Свой эдж точно измерить нельзя, поэтому дробный Келли и учебные 1–2% риска — это математически обоснованный ответ на неопределённость, а не робость.

  5. Скучный, маленький размер позиции — это не отсутствие смелости. Это единственный размер, который защищён математикой.


Я делаю бесплатные калькуляторы риск-менеджмента для крипто-трейдинга, в том числе симулятор Монте-Карло вроде этого, но интерактивный — riskdesks.com. Это единственная ссылка в статье.

P.S. Код и сид открыты, симуляцию можно повторить за минуту. Если найдёте ошибку в построении, в математике или сможете показать, что честность сравнения где-то нарушена — напишите в комментариях, поправлю прямо в статье и укажу автора правки. Это ровно тот peer-review, ради которого пост и написан: ломайте методологию, а не верьте на слово.

ссылка на оригинал статьи https://habr.com/ru/articles/1047262/