← Назад

Learnings — Grабли, баги, открытия

Автоматически пополняется Бендером после каждого бага/фикса/открытия. Порог ротации: 150+ записей — разбить по проектам или архивировать старые. Читается в начале каждой сессии.

[futures-screener] || null вместо ?? null — funding=0 теряется (falsy-zero bug)

Грабля: fundingMap.get(symbol) || null — если funding rate ровно 0 (нормально в flat рынке), 0 falsy → заменяется на null → funding context никогда не срабатывает для таких символов. Решение: rawFunding != null ? rawFunding * 100 : null — явная проверка на null/undefined.

[futures-screener] Дубль API call из-за несовпадающих cache key

Грабля: signals.js кэширует premiumIndex под ключом 'funding_rates', liq-sweep читал 'premiumIndex' → всегда cache miss → лишний API call каждые 60с. Решение: Передавать getFundingMap как dep через dependency injection, не дублировать fetch.

[options-screener] Math.abs() для NEUTRAL P&L = фейковый 100% Win Rate

Грабля: outcomeTracker использовал Math.abs(rawPct) для NEUTRAL direction (straddle/strangle), что всегда давало положительный P&L → 100% WR. 112 сигналов были фейково WIN. Решение: Каждая нога считается отдельно: callDelta×spotMove - callPremium + putDelta×spotMove - putPremium. Пересчитано → WR 57%→44%. Запомнить: Math.abs() для P&L = мгновенно подозрительно. Всегда проверять edge cases с NEUTRAL/bi-directional стратегиями.

[options-screener] Binance maxPrice может быть ниже lastPrice опциона

Грабля: SOL PUT lastPrice=$0.56 но maxPrice=$0.51. BUY LIMIT по lastPrice = "Price greater than max price". TP тоже клампится → +39% вместо +100%. Решение: clampPrice() для entry + TP room check: если maxPrice не позволяет ≥50% gain — сделка пропускается. Запомнить: Binance eAPI PRICE_FILTER maxPrice — обязательно проверять перед ордером. TP room = entry×1.5 ≤ maxPrice.

[futures-screener] Binance WS: legacy /stream депрекейтнут для klines 15m+

Грабля: Графики на 15m, 1h, 4h, 1d перестали обновляться live. Legacy endpoint wss://fstream.binance.com/stream перестал отдавать kline данные для таймфреймов ≥15m. 1m/5m продолжали работать. Решение: Миграция на wss://fstream.binance.com/market/stream (роутированный endpoint). Подтверждено тестами: legacy=0 тиков, market=20 тиков за 12с. Запомнить: Binance перевели WS на роутированные endpoints (/public, /market, /private). Klines → /market/stream. Проверять доки при WS проблемах.

[polymarket] ПРАВИЛО: Никогда не использовать токен Бендера для сторонних ботов

Грабля: Потенциальный риск — использование Telegram токена Бендера (claude-code-telegram) для нотификаций в других проектах. Решение: Каждый проект (weather-bot, btc-5m-bot, etc.) — свой отдельный Telegram бот ИЛИ веб-интерфейс. Бендер = только Бендер. Запомнить: НИКОГДА не использовать токен Бендера для сторонних ботов без ЯВНОГО разрешения Rick'а.

[futures-screener] WS: UNSUBSCRIBE/SUBSCRIBE на том же соединении — race condition

Грабля: При смене TF отправляли UNSUBSCRIBE старых стримов и SUBSCRIBE новых на том же WS соединении. На некоторых TF тики не приходили — race condition между unsub и resub. Решение: Полностью убивать WS (ws.close(), mc.ws = null) и создавать новое соединение. Плюс RE-SUB safety net (если 0 тиков через 5с — пересоздать стримы из видимых чартов). Запомнить: При смене контекста WS проще kill+recreate чем unsub+resub. Добавлять safety net timeout.

[futures-screener] Sorted-merge кластеризация имеет chain-merge problem

Грабля: Sorted-merge для S/R уровней мёрджил пивоты "цепочкой" — каждый следующий "чуть ближе" к предыдущему, в итоге крайние точки кластера далеко друг от друга. Решение: Заменили на DBSCAN (inline, без npm — клиентский код). Каждая точка проверяется от каждой, кластер реально плотный. Запомнить: Для кластеризации ценовых данных использовать DBSCAN, не sorted-merge.

[futures-screener] Auto trendlines допускали 15% violations — линии "через свечи"

Грабля: Старый алгоритм разрешал 15% свечей пересекать трендлайн. Визуально — линия проходит через тело свечей, выглядит неправильно. Решение: Gradient descent slope optimization с ZERO violations (neurotrader888 подход). Также enforce slope direction: support slope>0, resistance slope<0. Запомнить: Трендлайн должен иметь 0 нарушений. Support = восходящая по лоям, Resistance = нисходящая по хаям.

[futures-screener] Не изобретай велосипед — ищи готовые алгоритмы

Грабля: Писали S/R и trendline алгоритмы с нуля, когда на GitHub полно проверенных реализаций (trendln 697★, neurotrader888 552★). Решение: Ресёрч → адаптация лучших подходов (DBSCAN, gradient descent, zigzag, volume profile). Запомнить: Перед написанием нетривиального алгоритма — 15 мин ресёрча на GitHub/TradingView.


[futures-screener] DrawingManager.handleClick() не создаёт рисунки

Грабля: lightweight-charts-drawing@0.1.1setActiveTool() просто хранит имя, handleClick() делает только selection Решение: Создавать вручную через ToolRegistry.createDrawing(type, id, anchors, style, opts) + manager.addDrawing(drawing) Запомнить: Библиотека drawing tools — обёртка, рисунки создаются через ToolRegistry, не через DrawingManager


[futures-screener] touchend preventDefault убивает subscribeClick

Грабля: Мобильный touchend handler вызывал preventDefault() — убивал синтетический click — библиотека не получала событие через chart.subscribeClick Решение: return early в touchend когда DrawingManager активен Запомнить: На мобилке preventDefault в touch-хэндлерах ломает синтетические клики LWC


[futures-screener] LWC v5 createTextWatermark крашит всё

Грабля: createTextWatermark() (v5 primitive API) бросал TypeError: attachPrimitive is not a function, крашил openCoinModal() целиком — чарт показывал 2-3 свечи вместо 1000 Решение: Обернуть в try/catch. rAF/double-rAF НЕ помогают — проблема не в размерах Запомнить: Всегда try/catch вокруг LWC v5 primitives (watermark, markers) — они могут крашить тихо


[futures-screener] lightweight-charts-drawing CDN несовместим с LWC v5

Грабля: CDN lightweight-charts-drawing@0.1.1 — v4-only, 404 на v5, мог ломать internals Решение: npm install + раздавать UMD локально через Fastify route Запомнить: Всегда раздавать JS библиотеки локально, не CDN — контроль версий


[futures-screener] CSS display:none ломает LWC createChart

Грабля: .mc-modal.hidden { display:none } — элемент вне layout, createChart получает size 0 Решение: visibility:hidden + opacity:0 + pointer-events:none — элемент всегда в layout Запомнить: LWC чарты нельзя создавать в display:none контейнерах


[futures-screener] WS Binance флапает без подписок

Грабля: WS подключался при старте без подписок → Binance закрывал idle соединение → reconnect loop каждые 5с Решение: Lazy connect при первом subscribe(), ping keepalive 3мин, race condition fix для concurrent subscribes в CONNECTING state Запомнить: Не подключать WS до первой подписки. Binance убивает idle WS.


[futures-screener] JWT_SECRET random при рестарте

Грабля: JWT_SECRET генерировался при старте → каждый PM2 restart сбрасывал все токены Решение: Фиксированный секрет через PM2 env var Запомнить: Секреты для JWT — ВСЕГДА через env, никогда random при старте


[futures-screener] Push toggle убивает другие устройства

Грабля: Один toggle "Browser notifications" управлял и in-tab toast и серверным push — выключение на десктопе убивало push на телефоне Решение: Разделить на signalNotifications (in-tab) и signalPush (серверный) — каждое устройство независимо Запомнить: Push и in-tab уведомления — разные вещи, разные toggles


[futures-screener] Binance IP бан при массовых запросах

Грабля: Конкурентность 10 + scan всех 537 символов при старте → IP забанен дважды Решение: Concurrency 10→3, 500ms delay, batch 10/20s pause, graceful skip на 429, skip unsubscribed symbols Запомнить: Binance банит IP агрессивно. Warmup: 10 sym/batch, 20s pause. Max concurrency 3.


[futures-screener] Memory leak — Maps без cleanup

Грабля: cache/proxyCache Maps не удаляли expired entries, books bids/asks без TTL → Heap 89% (133MB) Решение: Детерминированный cleanup каждые 10-30с, TTL на все кеши, removeAllListeners при WS reconnect Запомнить: Каждый Map/cache ОБЯЗАН иметь TTL + периодический cleanup. Проверять heap после рестарта.


[futures-screener] OI сигналы — high confidence = хуже результат

Грабля: High conf (80+) OI сигналы имели R:R 0.86 — экстремальные OI скачки запаздывают (уже поздно входить) Решение: Bell-curve: sweet spot 4-8% OI change → conf 67-78, >10% → conf падает Запомнить: Для запаздывающих индикаторов (OI) — экстремальные значения = хуже, средние = лучше


[futures-screener] Signal dedup — нестабильный ID

Грабля: signalId = sig.id + "_" + Date.now() → дедуп искал по sig.id без суффикса → 99.3% дублей Решение: Дедуп по стабильным полям: strategy + underlying в окне 6ч Запомнить: ID для дедупликации должен состоять из стабильных полей, не включать timestamp


[options-screener] Binance contract unit multiplier (XRP=100, DOGE=1000)

Грабля: Premium = per-contract, но XRP 1 контракт = 100 XRP → breakeven показывал $3.50 вместо $1.40 Решение: fetchContractUnits() из exchangeInfo, нормализация в buildTradeRec/PnL Calculator Запомнить: Binance options — ВСЕГДА делить premium на contractUnit для per-unit цены


[options-screener] Binance eAPI: realStrikeAmount vs realStrikePrice

Грабля: Код искал ex.realStrikeAmount, Binance отдаёт ex.realStrikePrice → фоллбек на strike → ROI 59,000% Решение: Считать intrinsic value самим, не доверять strikeResult от Binance Запомнить: Binance eAPI exercise history — поля именуются неочевидно, strikeResult ненадёжен


[options-screener] Покупка опциона = SL не нужен

Грабля: Gamma Play и Whale имели SL 50-70% — бессмысленно для покупки опционов (премия = max loss) Решение: slPct=100% для ВСЕХ типов покупки Запомнить: При покупке опционов SL не нужен — максимальный убыток = уплаченная премия


[options-screener] IV Skew не логировался в backtest

Грабля: IV Skew генерировался в dashboard.js, но не в scheduler.js → 0 записей в SignalLog Решение: Добавить генерацию в scheduler slowUpdate() Запомнить: Сигналы должны генерироваться в ОДНОМ месте (scheduler), не в UI-рендере


[trading-bot] Z-VWAP: Z > 2.5 = breakout, не mean reversion

Грабля: Бот входил при Z=4.75 (FFUSDT) — это breakout. WR 83.5% но PnL -$31 Решение: Z-cap 2.5 — skip при |Z| > 2.5 Запомнить: Для MR стратегий экстремальные Z-scores = momentum/breakout, не MR. Ограничивать сверху.


[trading-bot] EMA slope threshold слишком жёсткий

Грабля: EMA slope 0.05% за 3 свечи блокировал ВСЕ MR сигналы (229 скипов, 1 сделка/день) Решение: Порог 0.05% → 0.4%. Для MR когда цена ниже VWAP, EMA естественно падает Запомнить: EMA direction filter для MR должен быть мягким (0.3-0.5%), иначе блокирует всё


[trading-bot] Забыл return значение из функции → тихий краш

Грабля: Добавил ema_slope расчёт но забыл return из функции → NameError при распаковке → скан тихо крашился 35 мин Решение: Всегда проверять return tuple после добавления новых полей Запомнить: asyncio проглатывает NameError/TypeError в tasks — добавлять try/except с логированием


[trading-bot] Binance STOP_MARKET возвращает algoId, не orderId

Грабля: STOP_MARKET ордера возвращают algoId, conditional orders не видны в openOrders API Решение: Проверять позицию напрямую вместо ордера, sleep 0.5s после partial TP перед SL update Запомнить: Binance Futures conditional orders (STOP_MARKET/TAKE_PROFIT) — отдельный API, не в openOrders


[trading-bot] SL/TP reason перепутаны

Грабля: При пропаже позиции бот всегда писал Reason=SL, даже если TP сработал. 75/122 сделок неверно Решение: Проверять статус TP order перед записью reason Запомнить: Определять причину закрытия по статусу ордеров, не по отсутствию позиции


[trading-bot] TradFi перпы требуют отдельных agreements

Грабля: XAU/XAG/XAUT/PAXG/CL — error -4411 даже при подписанном TradFi agreement Решение: Все TradFi в blacklist Запомнить: Binance TradFi-перпы (металлы, нефть) требуют отдельных agreement'ов для каждого


[piewell] WordPress автор ID

Грабля: Статьи публиковались под ID=1 (личный serg5585) вместо ID=2 (PIEWell) Решение: Всегда post_author: 2 Запомнить: WordPress автор — ВСЕГДА ID=2 (PIEWell), никогда ID=1


[piewell] Amazon ASIN может быть мёртвым

Грабля: Holy Basil ASIN B001GAOGPU перестал работать — 404 Решение: curl-проверка перед вставкой, verified список в скилле Запомнить: ВСЕГДА проверять ASIN перед вставкой. Amazon удаляет товары без предупреждения.


[futures-screener] app.js не подключён в HTML — orphan file

Грабля: Определил escAttr() и lsSet() в app.js, но этот файл не загружается через <script> в index.html. Настройки, плотности и сигналы сломались — undefined functions. Решение: Перенести глобальные хелперы в inline <script> в index.html перед всеми модулями. Проверять порядок загрузки скриптов! Запомнить: ВСЕГДА проверять index.html на наличие <script src="..."> перед добавлением глобальных функций в файл.


[futures-screener] fs variable used before declaration

Грабля: const fs = require('fs') объявлен на строке 399, но density cache на строке 209 ссылается на fs.promises.writeFile — ReferenceError. Решение: Использовать require('fs').promises.writeFile inline в ранних функциях. Запомнить: В Node.js порядок const деклараций важен — нельзя ссылаться до объявления (TDZ).


[futures-screener] Fastify v5 cors в конструкторе игнорируется

Грабля: cors: { origin: '*' } в конструкторе Fastify v5 тихо игнорировалось — CORS не работал вообще. Решение: Установить @fastify/cors плагин и зарегистрировать через fastify.register(). Запомнить: Fastify v5 НЕ поддерживает cors в конструкторе. Всегда через @fastify/cors плагин.


[futures-screener] Binance WS лимит 200 стримов на соединение

Грабля: 536 depth стримов в одном WS → Binance дропает каждые 5с → reconnect loop, density не работает Решение: Класс BinanceWSConnection, max 190 стримов, автоматическое создание новых соединений Запомнить: Binance WS hard limit = 200 streams/connection. Всегда разбивать на несколько.


[futures-screener] IDB delta merge создаёт гэпы на графиках

Грабля: IndexedDB хранил старые свечи, delta fetch не всегда бриджил гэп (limit 500 < gap size), merge создавал дыры Решение: Убрали IDB tier полностью, Memory cache → Server SQLite напрямую (достаточно быстро) Запомнить: Сложный multi-tier cache с delta merge = источник багов. Если сервер быстрый — не усложнять.


[futures-screener] S/R тип по позиции, не по пивоту

Грабля: Тип уровня определялся по типу пивота (high=resistance, low=support). При пампе 142% все старые resistance оказывались ниже цены → фильтровались → 0 уровней Решение: Тип = позиция vs текущая цена: ниже = support, выше = resistance Запомнить: S/R тип всегда определять относительно текущей цены, не по исторической классификации.


[bender] Никогда не трогать свой код

Грабля: 31 Mar 2026 — Бендер отредактировал файлы в /home/app/claude-code-telegram/, сломал себя. Rick чинил СУТКИ. Решение: Абсолютный запрет на любые изменения в claude-code-telegram/ без явного разрешения Запомнить: НИКОГДА не трогать /home/app/claude-code-telegram/ — это мой собственный код, одна ошибка = сутки даунтайма

[weather-bot] Forecast cache не работал — API спам → 429 бан

Грабля: bot.py имел forecast_cache dict, но в else ветке всё равно вызывал get_forecast_and_probability() вместо использования кэша. 171 маркет × brackets = сотни запросов без паузы → Open-Meteo 429 бан. Решение: При cache hit — берём forecast_value+sigma из кэша, пересчитываем только probability для конкретного bracket threshold. Добавили retry 3x с backoff (5s→10s→20s) + global cooldown 5 мин. Запомнить: Всегда проверять что кэш РЕАЛЬНО используется в else-ветке, а не просто объявлен.

[weather-bot] Loguru дублирует строки в PM2

Грабля: loguru по умолчанию пишет в stderr (handler id=0). logger.add(file) добавляет второй handler. PM2 захватывает оба → каждая строка лога дважды. 7MB лога за 12 мин. Решение: logger.remove() перед logger.add() — убрать дефолтный stderr handler. Запомнить: При loguru + PM2 всегда делать logger.remove() первым делом.

[weather-bot] P&L формула: size ≠ shares в prediction markets

Грабля: Resolver считал profit = (1-price) × size, но size = доллары, а не кол-во shares. shares = size/price. Реальный P&L был в 10-100x неправильный. Решение: WIN: size × (1-price) / price, LOSS: -size (теряешь всю ставку). Запомнить: В prediction markets ВСЕГДА конвертировать dollars→shares перед расчётом P&L.

[weather-bot] Double-padding в probability: eq brackets 2x overestimated

Грабля: Для "exactly 21°C": threshold±0.5 → ±1.0 (двойной padding). Вероятность завышалась в 2 раза → фейковый edge → убыточные сделки. Решение: Один уровень padding: ±0.5 для eq, threshold_low-0.5/threshold_high+0.5 для between. Запомнить: Проверять формулы вероятности на конкретных числах перед деплоем.

[weather-bot] Sigma=1.5°F для same-day = overconfident model

Грабля: Модель думала что прогноз точен до ±1.5°F. Реально NWS MAE = 2.5-3°F. Результат: модель завышала вероятности узких brackets, создавала фейковый edge. Решение: Sigma увеличен в 2x (1.5→3.0, 2.0→3.5, etc.). Модель стала менее уверенной. Запомнить: Перед калибровкой модели — проверить реальные MAE данные (NWS, ECMWF).

[weather-bot] YES ставки при market<10% = гарантированный лосс

Грабля: 7 из 7 YES ставок при market_prob<10% проиграли. Модель систематически overconfident на low-prob events. Решение: Фильтр: не ставить YES когда рынок даёт <10%. Запомнить: Если рынок и модель оба говорят <10%, но модель говорит 30% — рынок прав.

[weather-bot] Sync requests.get() в async функции = crash loop

Грабля: 171 HTTP запросов через blocking requests.get() + time.sleep(1.0) в async event loop. Uvicorn зависает на 60-90с, PM2 убивает процесс → 21+ рестартов. Решение: asyncio.to_thread() для всех blocking вызовов (scan, forecast, place_bet, resolve). Запомнить: В FastAPI/asyncio НИКОГДА не использовать blocking calls напрямую. Всегда to_thread().