В первой части мы разобрали базовую идею: торговый советник — это не «робот, который торгует вместо вас», а система, которая получает рыночные данные, формирует сигнал (и объяснение), и показывает результат человеку.
Мы прошлись по минимальной архитектуре: модуль котировок → сборка промпта → вызов модели → сохранение результата → веб-интерфейс и уведомления. И отдельно отметили опциональный слой контекста — новости, которые можно добавлять в промпт в виде саммари.
Во второй части будет меньше «в целом» и больше практики: какие данные действительно нужны на старте, где вылезают нюансы API бирж, что хранить в базе, как не улететь в лимиты, и почему без кэша, логирования и ограничений ваш советник развалится ровно тогда, когда вы на него рассчитываете.
Какие данные брать на старте
На старте у вас есть три основных класса рыночных данных, которые можно получать с биржи через API. Самый понятный и распространённый — OHLCV-свечи: Open/High/Low/Close плюс объём за интервал. Это “сжатое” представление цены, которое удобно хранить, кэшировать и передавать в модель как стабильный кусок контекста (например, последние N свечей выбранного таймфрейма1).
Если нужно видеть, что происходит внутри свечи, подключают ленту сделок (trades / tape) — поток фактических исполнений: цена, количество, время (иногда сторона). Такой слой добавляет детализацию по активности и импульсам и обычно используется как более “зернистый” источник, чем свечи.
Третий вариант — стакан заявок (order book): уровни bid/ask и объёмы на каждом уровне. Это уже данные про микроструктуру и ликвидность: не “что произошло”, а “что сейчас стоит в очереди”. Обычно его берут как отдельный слой контекста, когда нужно учитывать глубину рынка, дисбаланс спрос/предложение и реакцию на уровни.
Пока остановимся на самом простом варианте — OHLCV-свечах. В своей реализации вы можете добавить и сделки, и стакан, но задача этой статьи — ознакомительно-образовательная: собрать понятный каркас и не утонуть в деталях.
Единый формат данных и история
Как только вы начинаете получать котировки не из одного места, всплывает неприятная реальность: разные источники дают одни и те же данные в разных форматах. Где-то свеча — это массив чисел, где-то объект с полями, где-то время в миллисекундах, где-то в секундах, а названия и порядок полей могут отличаться даже у «похожих» API.
Если не ввести единый формат на своей стороне, система быстро превращается в набор костылей: каждый новый источник тянет за собой отдельные парсеры, исключения и “особые случаи”. Поэтому в модуле получения котировок почти всегда нужен общий внутренний формат — минимально достаточный для дальнейшего анализа. Для нашего текущего уровня это обычно: инструмент, таймфрейм1, timestamp2, Open/High/Low/Close и Volume.
Отдельно стоит проговорить про исторические данные. «Текущее состояние рынка» — это хорошо, но без истории вы не сможете ни расширять анализ, ни проверять гипотезы, ни хотя бы корректно объяснять пользователю, почему сигнал выглядит так, а не иначе. Поэтому даже в простой реализации имеет смысл хранить историю свечей (или уметь быстро её догружать) и фиксировать, какие именно данные легли в основу конкретного сигнала.
Рейт-лимиты: почему это важно
Почти у каждой биржи есть ограничения на частоту запросов — рейт-лимиты. Причина проста: если дать всем клиентам бесконечно “дергать” котировки, API ляжет даже без DDoS.
В контексте советника это важно вдвойне. Запросы выполняются не непрерывно, а по таймеру — и если вы неправильно выбрали периодичность или умножили её на количество инструментов, вы очень быстро упрётесь в лимит. Результат обычно одинаковый: ошибки 429/ban на ключ, дырки в данных и «молчание» системы именно тогда, когда рынок двигается сильнее всего.
Рабочий подход здесь прагматичный: заранее считать бюджет запросов (периодичность × инструменты × типы данных), кэшировать результаты, не запрашивать одно и то же дважды, и корректно обрабатывать лимиты (backoff/повтор через паузу вместо спама запросами).
Промпт и нейросети: тот же API, другие правила
С получением данных разобрались — теперь можно переходить к следующему уровню: промпт и работа с нейросетями.
На первый взгляд это очень похоже на запрос котировок: снова API, снова ограничения по частоте, снова нужно думать о ретраях, таймаутах и кэше. Только вместо “дай свечи” у вас запрос вида “вот данные, вот контекст, верни сигнал и объяснение”.
Дальше начинаются отличия. У биржи ответ — это структура данных, у модели — результат интерпретации. Поэтому промпт становится контрактом, а не просто “текстом”, и к нему приходится относиться так же, как к формату данных: версионировать, проверять, ограничивать и логировать.
Момент, который сильно упрощает жизнь на интеграции: в промпте можно заранее зафиксировать структуру ответа. Например, попросить модель вернуть результат строго в JSON — с полями вроде signal, confidence и reasons. Это не “магия”, но как минимум дисциплинирует формат, а на стороне приложения даёт возможность автоматически парсить и валидировать ответы вместо того, чтобы разбирать свободный текст.
Отдельно стоит упомянуть MCP (Model Context Protocol): это подход/протокол, который помогает стандартизировать, как модели получают контекст и как подключаются внешние источники данных и инструменты. Даже если сейчас вы используете прямые вызовы конкретного API, держать в голове MCP-подобный слой полезно — он дисциплинирует архитектуру и упрощает расширение.
И да, в перспективе “аналитик” не обязан быть внешним сервисом. Если появятся ресурсы и мотивация, этот модуль можно заменить собственной моделью (или дообученной опенсорсной), не переписывая остальную систему — при условии, что интерфейсы изначально разделены правильно.
Хранилище: проще, чем кажется
На этом этапе у нас уже минимум два “массива” данных: рыночные свечи и результаты анализа. А если смотреть чуть вперёд — добавятся история новостей (и их саммари), плюс сохранение промптов/ответов модели для дебага и повторного анализа. Иными словами, данных становится достаточно много, и они появляются в разных местах конвейера.
Поэтому имеет смысл заранее подумать об унифицированном хранении. Специфика таких данных часто позволяет не тащить полноценную SQL-схему: во многих случаях хватает встраиваемой базы и простого ключ-значение подхода.
KV-хранилище (key-value) — это модель, где данные сохраняются как пары “ключ → значение”: по ключу вы быстро достаёте нужный объект (например, свечи для инструмента и таймфрейма1 за период, или результат анализа для конкретного запроса).
Интерфейс: минимум, без которого советник бесполезен
И наконец — интерфейс. В UI/UX сейчас не углубляемся, но напомню базовую мысль из первой части: как минимум нужен веб-интерфейс, а как приятное дополнение — уведомления в Telegram.
На практическом уровне пользователю нужны всего несколько вещей. Во-первых, видеть текущие сигналы и алерты (и быстро понимать, что “сейчас происходит”). Во-вторых, уметь запросить анализ по требованию — получить свежие данные и сигнал в один клик. И, в-третьих, настраивать систему: выбирать инструменты и источники данных, управлять API-ключами, и — что важно — редактировать промпты и параметры анализа, не лезя в код.
Ядро: “кольцо”, которое всё связывает
У Толкина было “одно кольцо, чтоб править всеми… и в темноте их связать”. В архитектуре советника это кольцо тоже есть — только без пафоса: ядро системы, которое держит все модули вместе.
Ядро отвечает не за анализ как таковой, а за лайфцикл: старт/стоп приложения, инициализацию зависимостей, планировщик задач, маршрутизацию запросов (по требованию и по расписанию), корректное завершение работы. Именно здесь решается, что и когда запускается, куда пишутся данные, и как компоненты общаются между собой, не превращаясь в клубок.
Если хотите добавлять новые источники котировок, менять LLM-провайдера, подключать новости и при этом не переписывать всё каждый раз — ядро должно быть простым, но строгим: модули — по интерфейсам, зависимости — явно, конфигурация — централизованно, а жизненный цикл — предсказуемо.
На этом месте можно остановиться и честно сказать: “скелет” советника уже виден. Данные приходят, промпт собирается, модель отвечает, результат сохраняется и показывается пользователю — и всё это держится на ядре, которое управляет жизненным циклом. В следующей статье я спущусь на уровень ниже: разберём технические детали реализации — как выглядит единый интерфейс источников котировок, как устроить кэш и ретраи, где хранить историю, как валидировать ответы модели (включая JSON-формат), и что делать, чтобы система не ломалась от лимитов, времени и «редких» ошибок.
Сноски
- Таймфрейм — это длительность одной свечи (интервал агрегации данных): например 1m, 5m, 1h, 1d. Он определяет, как именно “сжимается” поток цен в OHLCV.
- Timestamp — это метка времени (обычно в UTC), к которой привязана свеча/сделка. Классическая ошибка: перепутать секунды и миллисекунды (или локальное время и UTC), после чего данные «съезжают» и анализ ломается.
По материалам itprolab.dev
Читайте также
Принимаем оплату в bitcoin: Часть вторая. Инструменты и подготовка
Возможно мне не удалось напугать вас в достаточной степени, чтобы вы отказались от этой безумной идеи - принимать оплату в bitcoin. Ну тогда у меня для вас есть еще одна порция головной боли на пятую точку.
Принимаем оплату в bitcoin: Часть шестая. Нюансы, опять нюансы
В прошлой части мы остановились на том, что не плохо было бы узнать о факте платежа от bitcoind, вместо того, чтобы перебирать все выданные адреса.
