Привет, Хабр. Видел в интернете кейс. где сделали бота с LLM для торговли на Polymarket и он сделал $10k из $1k за месяц. Ну и чо бы не попробовать что то такое же сделать! Побочный проект, чисто по приколу. Вооружил его вирутальным стартовым капиталом — $100 нарисованных.

И вот на второй день этот несерьёзный проект показал +9% на счёте.

Сразу дисклеймер: я не трейдер. Вообще! Фрилансер-разработчик, IoT, телеграм-боты — это моё. А в трейдинге я плохо шарю, по-честному, и если в комментариях окажутся настоящие трейдеры и увидят очевидные глупости — это потому что я в этой теме очевидно глуп. Статья не про trading expertise (у меня её нет). Она про методологию измерения и про то, как я четыре раза подряд обманывал себя на ней. Тут у меня получше.

Обычно такой текст заканчивается на: «И вот как я поднял иксы на ставках». Но нет! Следующие две недели я доказывал себе, что эти 9% — не прибыль, а артефакт измерения, причем четыре раза подряд. Параметрика, риск-слой, LLM-как-трейдер, FLB-харвест. И каждый раз казалось — вот сейчас, ну вот же оно!... УВЫ.

TL;DR. Negative result. Если ждёте «как я поднял иксы» — закройте вкладку. Если интересно, как на живых (пусть и бумажных) деньгах отличить настоящий edge от артефакта измерения, и почему рынок прогнозов сопротивляется наивным подходам — добро пожаловать. Код открыт, цифры воспроизводятся.

Эпиграф для внимательного: у всех четырёх провалов один общий корень. Но назову не сразу — сначала нужно почувствовать, как легко в него провалиться.

0. Что такое Polymarket и почему казалось что тут есть деньги

Polymarket — рынок предсказаний. Контракт торгуется в диапазоне $0…$1, и цена читается как вероятность: 0.10 = «рынок оценивает шанс в 10%». Резолвится в $1 (да) или $0 (нет). Меня привлекла, так же, его прозрачность.

Гипотеза, запускающая 90% таких проектов (моего в том числе): толпа на рынках предсказаний систематически ошибается, а новостной поток + LLM позволяют поймать ошибку раньше рынка. В литературе даже есть имя для одной такой неэффективности — favorite-longshot bias (FLB): игроки переплачивают за маловероятные исходы. Бесплатный сыр, ну.

Сыр был в мышеловке (конечно жеж), а мышеловка — в моей собственной методике измерения.

1. Архитектура

Сам репозиторий
Стек намеренно скучный:

  • FastAPI — API-слой (api).

  • Aiogram 3 — телеграм-бот как фронт аналитики.

  • PostgreSQL — рынки, снапшоты цен, новости, анализы, сигналы, сделки.

  • Redis + Celery — worker + beat: инжест новостей, снятие снапшотов, генерация сигналов, мониторинг сделок.

  • Docker Composeseed — единственный источник правды по активной стратегии (dev-режим: БД периодически вайпается, миграций нет).

  • CometAPI — доступ к LLM. Две модели: дешёвая для релевантности новостей, сильная (Sonnet 4.6) для торговых решений.

Модули (app/modules/):

news_ingestion   → забор новостей, дедуп по хэшу
llm_analysis     → LLM оценивает новость: relevance, impact_direction,
                   impact_strength, confidence
signal_engine    → превращал анализ в "edge" и сигнал           (v1–v4)
paper_trading    → открывал/вёл/закрывал бумажные сделки         (v1–v4)
llm_trader       → LLM сам принимает ВСЕ торговые решения        (v5)
llm_scorer       → измерительный инструмент: грейдит решения      (v5)
analytics        → агрегаты для дашборда
market_data      → клиент Polymarket (Gamma / CLOB / Data API)
telegram_ui      → бот-меню

В v1–v4 конвейер линейный: новость → анализ → сигнал → сделка → дашборд. Развалился он не там, где я ожидал.

2. v1–v2: болезнь time_limit

Первая рабочая версия (коммит 3ed8777) имела весь конвейер. v2 закрывала сделки по take-profit, stop-loss либо тайм-ауту удержания. Всё как у людей.

Результат v2 (n=260 закрытых):

  • +$0.21 суммарно, средняя сделка +$0.0008, winrate 49%;

  • 100% сделок закрылись по тайм-ауту. TP/SL не сработали ни разу.

Сижу, смотрю на это и думаю — да быть такого не может! Ну хоть один раз! Замерил фактическую амплитуду цены за окно удержания (120 минут): медиана 0.7 п.п., максимум 7 п.п. А пороги стояли на 10/7 п.п. Пороги были математически недостижимы.
Короче - бот физически не мог по ним сработать. Я поставил TP так, чтобы он не мог сработать никогда. БРАВО :)

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

3. v3: +9% за два дня, которые оказались ничем

v3 (коммит 4c2d98d) починил пороги по измеренной амплитуде:

take_profit_abs:        0.02   (было 0.10)
stop_loss_abs:          0.015  (было 0.07)
max_holding_minutes:    240    (было 120)
default_position_size:  1.0    (было 0.1)

И стало красиво. Замер на n=1052 закрытых сделках:

  • механика ожила: TP 49%, SL 33%, time_limit 18%;

  • equity $109.03, +9% за два дня.

Если бы я остановился здесь — была бы статья «как я поднял 9% на Polymarket». Но обычно я двигался так: никогда не верить заголовочному PnL без разбивки по концентрации. И эта разбивка убила всё.

По рынкам: 2 рынка из 17 дали +$14.35, остальные 15 — −$6.10. Весь профит — в двух рынках. Главный герой:

US x Iran peace by May 31:  NO,  371 сделка,  winrate 94.6%,  +$10.55

По цене входа: весь профит сидел в одной полосе entry_price |0.10, 0.15) = +$10.33 на 394 сделках. Уберём её — оставшиеся 660 сделок дают −$1.98.

Так что тут произошло? Бот нашёл рынок, который почти наверняка резолвится в NO (мира с Ираном к 31 мая не будет), и 371 раз перезаходил в одну и ту же near-resolved позицию, собирая детерминированный календарный распад. winrate 94.6% — не навык, а структура почти-решённого рынка.

И тут я сначала предложил гениальное: «v4 = только NO». Неправильно — это бы УСИЛИЛО концентрацию на Иране. Направление — не рычаг, хорошо что не закодил.

4. Оказалось: один корень на четыре провала

Пора назвать то, что я обещал в эпиграфе. У всех провалов было два сросшихся корня.

Первый: я измерял отметку, а не исход

Бумажная сделка «оценивается» по текущей цене рынка (mark). Открыл NO по 0.10, цена уехала на 0.08 — на бумаге у тебя +$0.02 «прибыли». Но это же не прибыль, а переоценка позиции по текущему марку! Реализованный результат известен только в момент резолюции: $1 или $0.

Почти весь «edge» в v1–v5 был артефактом измерения по марку и по дрейфу цены на горизонте +Nч, а не по тому, чем рынок реально закончился. Календарный распад почти-решённого рынка по марку выглядит как стабильная прибыль. На этом и стоят иранские +$10.55.

Корень второй: формула edge была тавтологией

Открываю app/modules/signal_engine/service.py. Смотрю как считается edge. Вот формула (сохранена в git и в докстринге текущего no-op):

sign  = self._direction_sign(impact_direction)        # +1 / -1
strength = self._clamp01(impact_strength)              # 0..1 из LLM
delta = strength * confidence * 0.5 * sign             # масштаб конвикшена LLM
model_probability = self._clamp01(market_probability + delta)
edge = model_probability - market_probability

Подставляю одно в другое, пока clamp не упёрся в границу:

edge = (market_probability + delta) − market_probability = delta
     = strength · confidence · 0.5 · sign

Ещё разок: «edge» — это буквально собственная уверенность LLM ×0.5. Он НИКОГДА не сравнивается с исходом. То есть - замкнутый круг: модель уверена → значит есть edge → потому что модель уверена. Можно сколько угодно крутить пороги, поднимать min_edge, можно фильтровать по min_confidence. Но это не поможет, потому что величина, которую мы зовём «edge», не содержит информации о реальности. Это тавтология, замаскированная под метрику.

А вырождение clamp на краях ещё коварнее! Когда market_probability + delta упирается в 0 (низковероятный рынок, NO), clamp срезает model_probability в 0:

edge = 0 − market_probability = −market_probability

Самый большой по модулю edge — ровно у границы 0/1. А в paper_trading:

direction = "YES" if edge >= 0 else "NO"

На дешёвых лонгшотах edge всегда отрицательный → бот структурно всегда берёт NO. «100% NO на Иране» — артефакт клампа, а не стратегия, машинка по сбору распада была вшита в формулу. И вот так я её три недели принимал за альфу :)

А как должно было быть??

Edge на рынке предсказаний по определению — расхождение вашей независимой оценки вероятности с ценой:

edge = P_independent(event) − market_price

Оценка P_independent должна строиться БЕЗ участия рыночной цены. Варианты: базовая ставка по историческим аналогам (как часто события такого класса реально случались), внешняя предсказательная модель, ансамбль прогнозов, парсинг условий резолва. Моя формула вместо этого брала рыночную цену и прибавляла к ней конвикшен LLM. То есть P_independent была функцией от market_price, и edge схлопывался в тавтологию. Согласиться с ценой, которую толпа уже загнала в край — это, вообще то, не edge...

Если в оценке вероятности фигурирует текущая цена — это не независимая оценка, а дорогой способ согласиться с рынком.

5. v3, шестой день: волна, которую принимают за тренд

Прошло шесть дней. Equity рисовала «бычью» пилу: 100 → 93 → 104 → 96 → 108 → 98 → 111.

Соблазн назвать это растущим трендом — огромный. Особенно если ты только что выпустил релиз и хочется верить. И я в своем канале даже кликбейтовый пост писал. Тут разбивка — это суперпозиция двух процессов:

  1. conc_band (полоса 0.10–0.15, та самая иранская машинка распада): +$20.1 за 6 дней, ноль стоп-лоссов в большие дни — но нерепрезентативно и истекает 31 мая вместе с резолюцией.

  2. rest (настоящие направленные ставки движка): −$12.0 за 6 дней.

Equity растёт ТОЛЬКО потому, что +$20 распада обгоняют −$12 движка, а как закончится распад — закончится «тренд».

Нюанс: выкинув один день-провал (05-16: 384 стоп-лосса из 501, −$11.56), rest ≈ −$0.45 — на нормальных днях движок около нуля, но регулярно ловит неконтролируемый коррелированный хвост (~раз в 6 дней; YES-лонгшоты — спортивные фавориты + геополитика — двигаются вместе в risk-off дни). Тут нет ни edge, ни контроля хвоста.

6. v4: строим риск-слой и получаем неопровержимую улику

Решил добавить структурный риск-слой, не трогая пороги (коммит 720e642). Три гварда в paper_trading:

daily_loss_limit_abs           = 5.0   # дневной ранний стоп
max_trades_per_market_per_day  = 10    # потолок перезаходов в один рынок
max_same_direction_open        = 10    # анти-корреляционный гвард

v4 не создаёт edge — она снимает маску концентрации, чтобы стала видна истинная ожидаемость движка. Замер v4 (n=288 за ~5 дней), и доказательства её отсутствия:

(1) Та же ставка — перевёрнутый знак. Тот самый иранский рынок:

US x Iran peace by May 31:
  v3:  +$10.55,  winrate 94.6%
  v4:  −$2.80,   winrate 16.7%

Тот же рынок и тот же движок, а знак перевернулся за дни.

В v3 он ловил удачу распада, в v4 потолок перезаходов это убрал, и «навык» испарился. Был бы это edge — он бы не зависел от того, разрешил ли я заходить 371 раз или 10, dtlm edge от количества заходов не зависит, а сбор премии распада — да.

(2) Бимодальный winrate. Рынки кучкуются на 62–100% ИЛИ 0–17%. Ни одного в зоне «навыка» 45–58%. Это лотерея направления дрейфа, а не предсказание.

(3) Профит снова концентрирован: 2 рынка (Spurs +$3.64, Iran-2027 +$1.56) = +$5.2, весь остальной стакан = −$2.32.

Неожиданный прикол — иллюстрация закона Литтла: потолок перезаходов срезал rate входов ~в 9 раз, и среднее число открытых позиций упало с 16 до 3. «16 открытых» в v3 были не диверсификацией.

Вывод: параметрическая глава закрыта. Никакая настройка порогов / направления / размера не создаёт edge — проблема выше по течению, в фейковой формуле.

7. v5: «Отдадим всё LLM» и нарвёмся на инверсную калибровку

Логичный шаг: убрать фейковую формулу совсем. v5 (коммит ea1847a) — параметрический торговый код выходит на пенсию (signal_engine и paper_trading — inert no-op), а ВСЕ решения (открыть/закрыть/держать/изменить, сторона, размер, риск) принимает LLM-трейдер. Ноль кодовых риск-лимитов, единственный инвариант — не заполнять сделку по невалидной цене, это защита от мусорного PnL. Каждое решение логируется в новую таблицу llm_decisions.

Первый же поведенческий сигнал (n=5) был ну прям дежавю: LLM сам, за часы, переоткрыл ловушку распада. Все 4 позиции NO на низковероятных рынках (p0 = 0.295, 0.155, 0.152, 0.008). Позиция по 0.008 — это максимум +$0.08 против −$9.92 риска! Справедливости ради, одно его решение было корректным hold с формулировкой «цена уже у пола, edge нет». То есть распознать ловушку он МОЖЕТ, просто непоследовательно. Ну прям как я!

Замер v5 показал инверсную калибровку: в зоне core (p0 0.15–0.85) рынок шёл против решений модели ~70% времени. В полосе максимальной уверенности [0.70, 0.85] — 1 из 10 благоприятных на +1ч и 0 из 9 на +4ч. То есть - модель ошибалась сильнее всего там, где была увереннее всего.

Честная оговорка, без которой раздел разваливается. Я только что (раздел 4) объявил: мерить надо ИСХОД, а не марк или дрейф на +Nч, и тут же строю вердикт v5 ровно на горизонтах +1ч/+4ч. То есть на марках, тот же самый корневой баг измерения.

Поэтому вот что:

  • n=18 направленных решений — это не выборка для калибровочного утверждения. На 18 точках любой паттерн чувствителен к 1-2 рынкам. «p ≈ 0.2%» формально считается, но статистически это сигнал, а не доказательство — для устойчивого вывода нужен n ≥ 100.

  • Разбивку по рынкам я привести не могу — серверную БД v5 я стёр до того, как осознал важность пересчёта к исходам. Тут так: если те 18 решений были по 3-5 рынкам — я мерил удачу на этих рынках, а не калибровку модели. Это ограничение, и я его не закрываю :(

  • Поэтому снижаю риторику: v5 дала сигнал инверсной калибровки на марк-горизонтах, согласующийся с последующим честным замером, однако сам по себе он недостаточен. Чистый вердикт дал только replay к резолюции в v6, вот именно осознание слабости v5-замера и заставило меня построить v6 правильно.

Заголовочная equity v5 ($85.66 → $108.33 за неделю) — шум марка на n=18. 

8. v6: последняя честная гипотеза и как её правильно убить

Я смешивал два утверждения:

  • (A) «модель умеет прогнозировать» — опровергнуто;

  • (B) «входы fade-the-longshot, к которым вёл клампа, имеют реализованный edge» — а вот это к резолюции ни разу чисто не мерилось.

FLB — реальная вещь из литературы! Может, иранские +$10.55 были настоящим харвестом FLB, просто я случайно его собирал? Два победителя — это survivorship, не доказательство, это надо проверить чисто!

Математика всё решает, ибо царица наук

Продать YES-контракт по цене p = взять сторону NO. Выплата: +p, если резолв NO (вероятность 1−q), и −(1−p), если YES (вероятность q), где q — эмпирическая частота срабатывания лонгшота. Ожидание на контракт:

EV = (1−q)·p + q·(−(1−p)) = p − q

+EV тогда и только тогда, когда p > q. То есть лонгшоты систематически ПЕРЕоценены. Чистый тайм-распад — мартингейл, в ноль на справедливой книге. Edge ограничен размером мисприсинга и ОБЯЗАН побить спред! Ну обязан же...

«Починим правилами, чтобы увернуться от хвоста» — самоподрыв: отфильтровать «новостные» лонгшоты = протащить обратно claim-A («модель умеет прогнозировать новости»), уже мёртвый.

Survivorship-free replay

Офлайн-харнес app/research/flb_replay.py (коммит 04a706a) не ходит в БД и ничего не пишет — только читает публичный API. Реальная воронка (числа из реального прогона):

2100  закрытых рынков, вытянутых из Gamma (closed=true, по убыванию объёма)
1202  бинарных Yes/No
1202  резолвнулись чисто в ~0/1   (ambiguous: 0, malformed: 0)
1176  с YES-токеном, датой резолва и объёмом ≥ $10k
 400  топ по объёму — прогон сэмплил их (max_markets)
  48  имели тик цены в полосе [0.05, 0.15] с runway (7, 90]d  → сработали

Для каждого сработавшего: вход — первая точка в полосе (ex-ante, исход не подсматривается), скоринг — к РЕАЛЬНОЙ резолюции из outcomePrices. Чистые функции покрыты юнит-тестами (tests/unit/research/test_flb_replay.py): парсинг исходов, ex-ante вход без look-ahead, тождество mean_pnl == p̄ − q при нулевом спреде.

Базовый якорь: по всем 1202 бинарным рынкам безусловный YES-rate = 318/1202 = 26.5%. Триггер «лонгшот» опускает q до 10–21% — то есть он действительно отбирает низковероятные рынки, как задумано. Ну это я хотя бы не наврал!

Три прогона — и приговор

прогон

вселенная / вход

n

p̄ (цена)

q (выбило YES)

gross edge

@ спред 2c

исходный

ликвид, earliest-in-band

48

0.104

0.208

−0.105

−0.11

stable

ликвид, сидит в полосе ≥14д

52

0.081

0.096

−0.015

−0.025

tail

ликвид, vol $2k–50k**

58

0.111

0.103

+0.008

−0.002

Что тут вообще:

  • Ликвид — анти-FLB. Лонгшоты по ~10% выбивали YES в 20.8%. То есть они НЕДОоценены, а не переоценены. Тут фейд теряет −0.105 на контракт, а ликвид — единственное место, где можно реально разместить капитал.

  • Фильтр стабильности работает как сигнал, но приземляется на справедливую цену. Требование «цена сидела в полосе ≥14 дней» (это стилман моего же v6-правила про календарный распад без новостей) срезало q с 0.208 до 0.096 — вычистило climbers и news-волатильность. Фильтр молодчик, короче! Но q (9.6%) ≈ p̄ (8.1%): премии для «страховщика» под спокойными лонгшотами нет, цена справедливая.

  • Остаток FLB живёт в illiquid-хвосте (p̄ 11.1% > q 10.3%) — ровно как предсказывает теория (шарпам невыгодно чинить мелкие рынки). Но он (а) статистически ноль (при n=58 σ(q) ≈ 0.039, edge 0.0078 ≈ 1/5 сигмы), и (б) экономически мёртв.

Ограничения, к которым я пришел:

  1. outcomePrices принимаются как истина без аудита UMA-историй. UMA-резолв исторически имел спорные кейсы (определения «happens», временны́е границы, ручные оверрайды). В моей видимой выборке 0% неоднозначных резолвов — но это потому, что closed=true по построению отдаёт только формально-резолвнутые, а диспьюты я не аудировал.

  2. Selection bias вселенной. Воид/отменённые/зависшие-нерезолвнутые лонгшоты в closed=true не попадают вовсе и их долю отсюда не видно, ведь лонгшоты снимаются чаще среднего — значит часть вселенной я просто не вижу. Направление биаса, скорее, консервативно к моему выводу: если воиднутые лонгшоты — это в основном несостоявшиеся события (были бы NO), их исключение завышает измеренный q и делает мой анти-FLB-результат ещё пессимистичнее для стратегии, но без аудита пропущенного это догадка.

  3. Earliest-in-band — оптимистичная цена входа. Я вхожу в момент первого касания полосы, но в реальной торговле сигнал был бы позже (увидеть → подтвердить → исполнить), а на illiquid-рынках разница в днях — это другая цена и другой q. Sensitivity по delayed-entry я не гонял, приведённый gross edge — это ВЕРХНЯЯ оценка, лучший случай для стратегии и даже верхняя оценка ≤ 0 после спреда.

  4. Спред в хвосте занижен референсом. Брейкивен illiquid-прогона = 2 × gross = 2 × 0.0078 ≈ 0.0156 (1.6c). В модели платишь полспреда на входе и держишь до резолюции, без спреда на выходе, а на лонгшотах с объёмом $2–10k реальный bid-ask чаще 8–20c плюс слиппедж от собственного ордера. Вот вам точная формулировка: edge мёртв при любом реалистичном спреде — точка безубыточности 1.6c, а такого спреда на этих рынках не бывает.

v6 не построен. Закрыт ДО единой строчки торгового кода.

9. Технические засады в API Polymarket

Несколько вещей, на которых я потерял время:

  • Gamma кодирует списочные поля как JSON-строки. outcomesoutcomePricesclobTokenIds приходят строками вида '["Yes", "No"]'. Нужен ручной json.loads. Прям как в нулевых.

  • Gamma отдаёт 422 на большом offset. Это конец пагинации, не ошибка! Ловите и останавливайтесь.

  • CLOB /prices-history режет окно ~14 днями независимо от fidelityinterval=max/1d/1w для тестовых токенов возвращал пусто. Лечится чанкингом по 13 дней со склейкой и дедупом по timestamp. Голый except: returnэто глушил и давал «0 сработало».

  • Offset-пагинация упирается в ~2100 строк на направление. Mid-tail (vol $2k–50k) сидит МЕЖДУ «верхними 2100» и «нижними 2100» и недостижим через offset. Достаётся серверным фильтром volume_num_min / volume_num_max.

10. Почему это не работает: синтез

Три независимые главы — параметрика (v1–v4), LLM-как-трейдер (v5), FLB-харвест (v6) — дали no/negative edge. Складываем:

  1. Не было модели. Формула edge была тавтологией (конвикшен LLM ×0.5), не сравнённой с реальностью.

  2. «Прибыль» была артефактом измерения. Календарный распад почти-решённых рынков по марку маскировался под альфу; survivorship по двум победителям достраивал иллюзию.

  3. LLM не спасает. Сильная модель не создаёт edge автоматически — v5 дала сигнал инверсной калибровки (на крошечной выборке).

  4. FLB неторгуем. Там, где ликвидно — его нет или он обратный. Где он шепчет (хвост) — он ниже стоимости транзакции.

И сразу — чего я НЕ доказал. «Рынок эффективен» — утверждение сильнее моих данных. Я показал ровно следующее: в той части рынка, где можно разместить капитал, методы, которые я пробовал (predictive-бот на новостях + ex-ante FLB-харвест), edge не дают, но это не исключает других ниш, которые мой опыт просто не покрывает:

  • resolution arbitrage — LLM парсит точные условия UMA-резолва и ловит расхождение буквы условия с тем, как рынок его понимает;

  • cross-market coherence — арбитраж логически связанных рынков (если A⇒B, цены должны быть согласованы, и если нет — есть бесплатные деньги);

  • market making на широких спредах в хвосте.

Их держите отдельно от моего вывода — я их не трогал.

11. Что я вынес: методология дороже стратегии

Стратегии у меня нет, а вот метод — есть. И он, по-моему, ценнее самой стратегии:

  • Никогда не верь заголовочному PnL. Первое — разбивка по концентрации (по рынкам и по полосам цены входа). Один-два рынка, делающие весь результат — красный флаг survivorship. Если бы я в первый день после +9% не пошёл в разбивку, я бы реально публиковал статью о «успехе».

  • Измеряй ИСХОД, а не отметку. Единственная честная метрика — survivorship-free replay к реальной резолюции, так как марки и +Nч-дрейф врут систематически в одну сторону.

  • Перед настройкой порогов измерь распределение того, что они ловят. Если бы я это сделал в v1, не было бы v2.

  • Различай «баг измерения» и «отсутствие edge». Я честно смешал их в v3/v4 (и в v5) и потерял время. Чистый тест каждой гипотезы по отдельности экономит недели.

  • Negative result — это результат. Четыре гипотезы закрыты и могу написать об этом статью.

Контрфактическое

Ели бы я остановился на втором дне, опубликовал «+9% за два дня», вечером того же дня прочитал статью про favorite-longshot bias. И решил бы: «Ого, я случайно делаю именно это! Бесплатные деньги!». Я поверил в свой edge, и, блин, вполне возможно — занёс бы на этот рынок реальные деньги, а через две недели потерял бы их на флипе иранского рынка после первой реальной новости.

Защищает одна привычка: разбей PnL и измерь к исходу, прежде чем поверить себе.

Эта статья — лог того, как эта привычка четыре раза спасала меня от собственного оптимизма.

12. Масштаб и репозиторий

Фейковый капитал — стартовые $100, ноль реализованного edge на выходе.

Расход на LLM-токены — $20, из них $13 — Claude Sonnet 4.6 по $2.40/Mtok (трейдер-LLM). Остальное — ChatGPT 5.1 для оценки релевантности новостей.

Это 20% от paper-капитала, ушедшие на инференс ради количественного нуля. Если читать как unit economics реального проекта — даже идеальная стратегия с 20% APR на $100 капитала просто окупила бы токены, и не принесла бы ничего сверху.

Одностишная мораль для подобных проектов: слил $20 на LLM, чтобы количественно показать ноль на бумажных $100.

Открыты: код, журнал стратегий с замерами по каждой версии (docs/STRATEGY_JOURNAL.md), полный отчёт по FLB pre-mortem (docs/research/flb_pre_mortem.md) и воспроизводимый харнес.

Навигация по эволюции:

3ed8777  начальный конвейер (v1/v2)
4c2d98d  v3: пороги по измеренной амплитуде
720e642  v4: структурный риск-слой
ea1847a  v5: pivot на LLM-as-trader
c9722f3  v5: скорер (калибровка + edge)
04a706a  v6: survivorship-free FLB replay

Проект разрабатывался в плотной паре с Claude Code - это не вайбкодинг ради хайпа! Вся аналитика, замеры, разбор кода и формулировки — мои, но писались и проверялись в диалоге. Результаты подобных экспериментов и мысли выкладываю тут