Skip to content

v0.4.1

Choose a tag to compare

@github-actions github-actions released this 19 Sep 09:05
· 16 commits to main since this release

[0.4.1] - 2026-09-19

Влияние: торговая логика (бот 1) · P&L · UI · настройки/данные - бот 1 перестал
считать удар по рынку плоской константой 0.1% и берёт измеренную кривую глубины GMX. Константа
берёт 10 базисных пунктов, а измеренная величина на тикете $2500 это медиана 0.001 бп (ровно ноль
у 57 наблюдений из 126) при максимуме 13.38: константа выше измеренного в 125 наблюдениях из 126,
и вместе с ней завышен круг издержек, из-за чего правило отказывалось от рынков,
которые окупались бы: замер на 63 рынках при капитале $2500 даёт $840.30 нетто за год против
$775.84
, то есть +$64.46. Круг сделки при $2500 стал около $6.3-6.9 вместо $8.75. Заодно
леджер перестал списывать своё число и книжит ровно тот круг, на котором принято решение.

Что увидит владелец открытой сделки при обновлении. Уже открытая позиция не трогается: её круг
списан и заморожен в момент входа. Изменится СЛЕДУЮЩЕЕ решение: круг подешевеет, и в состав
кандидатов вернутся рынки, которые прежний круг отсекал. В карточке издержек статья
«проскальзывание GMX» получила пометку, что правило входа и леджер её больше не берут, когда у
рынка есть измеренная кривая; само поле осталось редактируемым.

Клиенту, который стоит на 0.3.1. Обновление приведёт сразу сюда, минуя промежуточные версии,
поэтому для него действуют ЧЕТЫРЕ секции: 0.3.2 и 0.3.3 (они так и не публиковались), 0.4.0 и эта.
Главное из пропущенного: бот 1 перестал считать по пяти зашитым рынкам и собирает вселенную живым
отбором, плюс аудит механики 18.09 и починка его находок. Полный текст всех секций лежит в
CHANGELOG.md.

Проверено живьём на боевой машине 18.09 в 21:14Z: первое решение с кривой вошло в рынок,
которого в снимке нет вовсе (Avalanche, запасная кривая по ярусу ликвидности), круг сделки $6.32
вместо $8.75, и три числа сошлись между собой - круг правила в записи решения, списание позиции и
статьи в паспорте сделки.

Исправлено

  • [Funding-Arb] Кривая удара GMX дошла до живого тракта. slice.js подавал в правило
    impact: { gmxNodes: [] }, и пустые узлы означали НЕ ноль издержки, а плоскую константу
    gmxImpact 0.1% из costs.js: пустая кривая выключает ветку hasGmxCurve в costAtSize, и круг
    считается по константе. Константа берёт 10 базисных пунктов, а измеренная величина на тикете
    $2500 это медиана 0.001 бп (ровно ноль у 57 наблюдений из 126) при максимуме 13.38, то есть
    константа завышала круг издержек почти везде. Цена, названная отчётом
    фазы 3: -$64.46 нетто за год на 63 рынках при капитале $2500 ($840.30 против $775.84), и она
    РОСЛА С ЧИСЛОМ РЫНКОВ, потому что завышенный круг отсекает ровно те рынки, где нетто и круг
    сопоставимы, - а вселенная как раз выкачена на полусотню.

    Измеренный снимок глубины (impact-gmx.json.gz, 63 рынка Arbitrum, 623 256 наблюдений за год)
    лёг в данные приложения src/engine/fa/data/, откуда его пакует electron-builder без правки
    конфигурации (files: ["src/**/*"]). Узлы приносит новый читатель fa/impact-curve.js, файл
    открывает main/impact-load.js: срез остаётся ЧИСТЫМ, как и был. Знак приводится в одном
    месте
    (Math.max(0, -(adverseBps ?? 0)), образец exit-lib.mjs loadCapacity): приведение
    дважды дало бы отрицательную издержку, то есть премию за собственный вход.

    Правила движка не тронуты ни строкой, и это проверено суммами: все шесть книг снялись ПОБИТОВО
    теми же
    (сверка прогонов до и после правки, sha256 совпали у каждой). Это и есть доказательство,
    что правка живёт в срезе, а не в правиле. Замер эффекта на трёх годовых фикстурах книгой правила
    входа против её же контроля --drop-rule impact-off: нетто $1354.79 против $1297.52 (+$57.27),
    круг издержек $240.84 против $283.28, профинансировано 16 решений из 33 против 14. Два рынка
    (ETH блок 3, BTC блок 9) плоская константа отвергала кодом below_fund_ratio, а с измеренной
    кривой они проходят.

  • [Funding-Arb] Рынок, которого в снимке нет, получил НАЗВАННЫЙ запасной путь вместо молчаливой
    подстановки.
    Это не краевой случай: на живом составе фикстуры 16.09 снимок не покрывает
    16 инструментов из 51 (31%) - четыре рынка Avalanche (снимок снят по Arbitrum, и глубина рынка
    ETH на Avalanche это не глубина ETH на Arbitrum) и двенадцать листингов Arbitrum новее периода
    снимка (VVV, XMR, ZEC, XPL, SKY, AERO, HBAR, MET, PUMP, ICP, LIT, CC). Источник кривой каждой
    строки едет в live.gmxCurveSrc (market, tier, pooled, none), и молчаливого источника
    нет ни у одной.

    Обе ветки замерены методом исключения по очереди на тех 63 рынках, где правда известна
    (тикет $2500, 126 наблюдений, |ошибка| в бп за круг): запасной путь по ярусу ликвидности даёт
    медиану 0.07 (p95 2.58), по общему пулу 0.06 (p95 2.61), плоская константа - 10.00
    (p95 10.00). Константа переоценивает удар в 125 наблюдениях из 126. Ветка ОТКАЗА (код
    univ_no_impact_curve) отклонена замером: она сняла бы с вселенной те самые 31% инструментов,
    включая все рынки Avalanche и каждый новый листинг навсегда, то есть отменила бы фазу 3 тем
    незаметнее, чем дальше снимок от сегодняшнего дня. Ветка none оставлена достижимой и под тестом.

    Граница названа честно: запасная кривая это ЦЕНТР яруса, поэтому на тесных рынках она удар
    НЕДООЦЕНИВАЕТ - в ярусе D_<200k 15% наблюдений недооценены больше чем на 0.5 бп, худшее 13.22 бп;
    в ярусах A и B недооценки нет (максимум 0.07 и 0.74 бп). Новый листинг почти всегда тесный, то
    есть попадает ровно в тот ярус, где запас слабее всего. Это повод пересчитывать снимок, а не
    считать его вечным.

  • [Funding-Arb] У снимка глубины появился срок годности, а у записи решения дата снимка и
    источник кривой каждого рынка.
    Возраст считается от КОНЦА ПЕРИОДА снимка, а не от дня съёмки:
    снимок снят 30.08, но посчитан по истории до 20.06, то есть в день рождения уже отставал от рынка
    на 71 сутки. Конец периода лежит в самом файле числом (meta.period), поэтому вбивать дату
    константой и следить, чтобы она не разъехалась с файлом, не нужно. Срок 180 суток, для
    нынешнего снимка это 17.12.2026. Он обоснован охватом: за 90 суток после конца периода живая
    вселенная набрала 13 имён Arbitrum, которых снимок не знает, и при том же темпе своя кривая
    рынка перестаёт покрывать хотя бы половину состава примерно на 170 сутки. Это ДОПУЩЕНИЕ: под ним
    одна скорость на одном промежутке, продолженная прямой, а второй механизм старения, дрейф глубины
    на покрытых рынках, не замерен ничем, потому что живьём удар не наблюдаем вовсе.

    После срока расчёт НЕ меняется, и это замер, а не смелость. Обе замены измерены и обе хуже:
    плоская константа ошибается в медиане на 10.00 бп против 0.07 у яруса, отказ рынку без своей
    кривой снимает 31% вселенной. Поэтому просрочка это сообщение: строка журнала на буте, флаг st
    в каждой записи решения и падение офлайн-смоука npm run smoke:impact кодом возврата. Неизвестный
    возраст считается просроченным, а не свежим.

    Запись решения понесла три новых числа: блок im с датой конца периода, возрастом снимка на
    час решения и флагом просрочки, плюс поле im с именем источника кривой у каждого рынка и
    каждого отказа. Без них круг издержек k в строке решения нечем объяснить задним числом: он
    посчитан либо по своей измеренной кривой рынка, либо по подстановке по ярусу, а по числам эти два
    решения неразличимы. Строка решения подорожала на 41 байт плюс 14 байт на рынок, решение одно в
    сутки, поэтому в таблице объёма сдвинулась одна сотая в клетке «63 рынка, опрос 1 мин»
    (35.66 МБ в сутки против 35.65). Правила движка снова не тронуты: шесть книг побитово те же.

  • [Funding-Arb] Леджер бумажной сделки списывает круг ПРАВИЛА, а не свой. Правка кривой
    развела решение и учёт, и до неё они сходились: правило считает круг по измеренным кривым (удар
    GMX из снимка глубины и стакан Hyperliquid), а faOpenFromIntent списывал его по плоской модели.
    Замер на живой записи: правило посчитало $7.36, леджер списал $8.75, из них $2.50 статьёй удара,
    которую правило на том же рынке оценило в $0.00. На 27 кругах в год это до $67 издержек, которых
    нет, то есть величина того же порядка, что и весь выигрыш кривой $64.46: бот зарабатывал бы
    решениями, а отчитывался бы по другому числу.

    Теперь openPosition получает intent.costUsd, то самое число, на котором принято решение.
    Пересчёта здесь нет и быть не должно: вторая копия расчёта круга разошлась бы с первой на
    следующей же правке. Статьи для леджера строит новый breakdownForTotal (costs.js): комиссии и
    газ точные из модели, всё, что правило насчитало сверх них, это измеренное проскальзывание обеих
    площадок одной строкой. Сумма статей сходится с кругом по построению (до ошибки округления
    двоичной дроби, 9e-16 на круге $7.36), и это важно: интерфейс леджера показывает Σ детализации
    рядом с кругом целиком. Круг ниже комиссий разбивки не даёт вовсе, чтобы не выдумывать
    отрицательную статью: так честнее, чем смешивать два числа в одной строке.

    Заодно починено, что запись сделки ПЕРЕСЧИТЫВАЛА статьи из текущих настроек вместо того,
    чтобы документировать списанное. Это врало и до кривой: модель издержек редактируема, и правка
    между открытием и записью переписала бы историю. Теперь статьи берутся с позиции, где они
    заморожены в момент входа. Проверено живьём: правило $6.57, позиция $6.57, запись $6.57, статья
    проскальзывания $0.32 против плоских $2.50 до правки.

    Подпись статьи в леджере стала «проскальзывание обеих площадок»: она больше не про одну GMX.

Добавлено

  • [Funding-Arb] Статья «проскальзывание GMX» в карточке издержек помечена как не работающая
    у правила входа.
    С появлением кривой эту статью берут не все потребители круга: costAtSize
    при живой кривой зануляет её и подставляет измеренное, а кривая сегодня есть у всех 54
    инструментов живого состава, то есть настроенное значение не влияет на выбор рынка ни разу. Круг
    в той же карточке и леджер бумажной сделки считают по нему по-прежнему, поэтому написано «правило
    входа не берёт», а не «не в силе»: статья в силе, но не у правила. Поле осталось редактируемым,
    числа не тронуты, текст едет и в aria-label.

  • [Funding-Arb] Офлайн-смоук npm run smoke:impact (scripts/smoke-fa-impact.mjs): показывает
    живой состав отбора со стороной ноги, источником кривой, ударом в базисных пунктах и кругом
    издержек с кривой и без неё. Падает кодом возврата, если снимок не прочитан или своя кривая не
    досталась никому. В сеть не ходит: кривая удара живьём не наблюдаема вовсе (в REST GMX нет ни
    одного поля impact), поэтому проверять надо путь снимка до правила, а не путь сети до снимка.