zipFinam — открытая Python-библиотека для бэктеста и алготорговли на Московской бирже:
котировки Финама, торговые календари MOEX и исполнение заявок через Finam Trade API.
Стратегия, проверенная на истории, без переписывания запускается на вашем счёте в Финаме.
Зачем это нужно · Котировки Финама · MOEX AlgoPack · Торговля на своём счёте · Начало работы · Лицензия
акции и фонды MOEX из Финам Trade API · календари MOEX и FORTS · заявки целыми лотами · капитал стратегии, а не весь счёт · данные MOEX AlgoPack по желанию · движок ziplime
Большинство инструментов для бэктеста сделаны для американского рынка. На Мосбирже с ними начинаются проблемы:
- Нет данных. Популярные бесплатные источники вроде
yfinanceроссийские бумаги толком не покрывают. - Свечей мало. OHLCV показывает, куда сходила цена, но не кто её двигал: агрессивный покупатель или пустой стакан, толпа или один крупный игрок.
- Тестер заглядывает в будущее. Биржевая статистика публикуется с задержкой, иногда пересчитывается задним числом, и наивный бэктест незаметно читает то, чего в тот момент ещё не было.
- От теста до торговли — вторая разработка. Стратегию, проверенную в одном инструменте, приходится переписывать под API брокера.
zipFinam закрывает все четыре проблемы.
Бары и справочник инструментов приходят напрямую из Финам Trade API: акции и фонды MOEX, таймфреймы от минуты до квартала. Нужен только токен из личного кабинета Финама.
cd examples
python ingest_finam.py # справочник инструментов и дневные бары
python run_backtest.py # бэктест на голубых фишкахФинам подключается к движку как штатный провайдер данных: get_market_data_source("finam")
работает так же, как встроенный Yahoo для американского рынка.
AlgoPack — аналитика, которую Мосбиржа считает по собственной ленте сделок и стакану. Их не восстановить по свечам или ленте: биржа видит каждую заявку, включая снятые. В zipFinam таблицы AlgoPack читаются той же строкой, что и цены:
# zipFinam достаточно установить: ziplime сам находит адреса algopack://
flow = await data.history(assets=[sber], fields=["disb", "val"], bar_count=5,
data_source="algopack://eq/tradestats")| Таблица | Что видит стратегия | Рынки |
|---|---|---|
tradestats |
Кто пересекал спред: объём агрессивных покупок против продаж (disb) |
акции, фьючерсы, валюта |
orderstats |
Какие заявки выставили и какие сняли: настоящий спрос против декорации | акции, фьючерсы, валюта |
obstats |
Спред в б.п., глубина и дисбаланс стакана каждые 5 минут | акции, фьючерсы, валюта |
hi2 |
Концентрация потока: покупает толпа или один игрок | акции, фьючерсы |
futoi |
Открытый интерес физлиц против юрлиц | фьючерсы |
alerts |
Сигналы биржи об аномальной активности | акции, фьючерсы, валюта |
Это главное отличие от самодельного парсера. Каждая строка AlgoPack становится видна стратегии в момент, когда биржа её опубликовала, а не в момент, к которому она относится:
- дневной итог виден на следующей сессии, а не в течение своей;
hi2биржа публикует примерно через шесть минут после своей метки времени, и раньше этого стратегия его не увидит;- строки, которые биржа пересчитала задним числом (бывает, спустя месяцы), не пропадают из бэктеста до даты пересчёта, а остаются на своём месте.
Сводка за сессию собрана по правилу для каждой колонки: объёмы суммируются, VWAP взвешиваются,
снимки стакана усредняются, дисбаланс пересчитывается по итогам дня. Агрегация сверена вручную
с реальными данными SBER. Нужны пятиминутки — algopack://eq/tradestats/5min.
Загруженная история кэшируется на диске: инструмент-год tradestats занимает около 3 МБ, и
повторный бэктест по тем же годам не скачивает их заново.
В examples/algorithms/algopack/ по стратегии на каждую таблицу:
| Стратегия | Идея |
|---|---|
flow_tilt |
Держать голубые фишки, которые покупают агрессивные деньги |
orderstats_conviction |
Покупать там, где выставленные биды не снимают |
obstats_liquidity |
Держать то, что поддерживает стакан, а не случайный принт ленты |
hi2_crowding |
Идти за бумагами, где покупает кто-то один против рассеянного рынка |
futoi_crowd |
Стоять против толпы физлиц во фьючерсе на доллар/рубль |
python run_backtest.py algorithms/algopack/flow_tilt.pyТа же стратегия, без изменений, торгует на вашем брокерском счёте в Финаме через Trade API. Укажите данные счёта и запустите пример:
export FINAM_TRADE_TOKEN=... # токен счёта, на котором исполняются заявки
export FINAM_ACCOUNT_ID=... # номер этого счёта
export FINAM_TRADE_URL=https://api.finam.ru # заявки уходят на ваш счёт
cd examples && python run_live_finam.pyИсполнение рассчитано на реальные деньги:
- Стратегии выделяется капитал, а не весь счёт.
order_target_percent(0.5)— это половина её бюджета, а не половина брокерского счёта. - Лоты. Объём округляется до целых лотов (GAZP — по 10 штук). Если размер лота неизвестен, заявка не отправляется вовсе: наугад ничего не торгуется.
- Принятая заявка ≠ исполненная. После каждого тика статус заявок запрашивается у брокера, и отклонённая заявка отмечается как ошибка, а не как успех.
pip install "zipfinam[all]"Создайте .env в рабочей папке:
GRPC_TOKEN=... # токен Финам Trade API: котировки, справочник, лоты
ALGOPACK_API=... # ключ MOEX AlgoPack, подписка на https://data.moex.comДля бэктестов на свечах хватит GRPC_TOKEN. Можно поставить не всё:
| Extra | Что добавляет |
|---|---|
| — | Данные Финама, календари, адреса algopack:// |
algopack |
Клиент MOEX AlgoPack |
live |
Исполнение заявок через Финам |
Стратегия — обычный Python:
from ziplime.finance.execution import MarketOrder
async def initialize(context):
context.stocks = [await context.symbol(s) for s in ("SBER@MISX", "GAZP@MISX")]
async def handle_data(context, data):
for stock in context.stocks:
bars = await data.history(assets=[stock], fields=["close"], bar_count=50)
if len(bars) < 50:
continue
closes = bars["close"].to_numpy()
target = 0.5 if closes[-20:].mean() > closes.mean() else 0.0
await context.order_target_percent(asset=stock, target=target, style=MarketOrder())Тикеры пишутся с кодом площадки (SBER@MISX). Имя context.assets занято движком, своим
переменным давайте другие имена.
Стандартный календарь XMOS заканчивается в 18:45, и фьючерсная стратегия теряет на нём вечернюю
сессию. zipFinam добавляет календарь FORTS (09:00–23:50, клиринг 18:50–19:05) и регистрирует в
ziplime площадки Мосбиржи: акции MISX живут по XMOS, срочный рынок RTSX — по FORTS. Каждая
бумага торгуется в часы своей площадки, а для портфеля из бумаг нескольких бирж ziplime подбирает
общий календарь: clock_calendar_name(["MISX", "XNYS"]) → 24/5.
zipFinam — надстройка над ziplime, открытым движком бэктестинга и живой торговли от Limex. Движок, метрики и модели исполнения берутся из ziplime, а zipFinam добавляет российский рынок: данные, календари и брокера.
zipfinam/
├── finam/ # Финам: бары, справочник, исполнение (REST и gRPC)
├── algopack/ # MOEX AlgoPack: каталог таблиц, клиент, источник данных
└── venue_calendars.py # календарь FORTS и площадки Мосбиржи для ziplime
examples/ # загрузка, бэктест, живая торговля, стратегии
Тесты работают без сети: pip install -e ".[dev]" && pytest.
Переход с версии 0.x и ограничения
- Нужен ziplime 2.11 или новее. Импорты:
from zipfinam import FinamDataSource, FinamAssetDataSource; старый модульziplime_grpc_data_sourceоставлен на время перехода. - Готовый
assets.sqliteбольше не поставляется: справочник загружается из Финама скриптомexamples/ingest_finam.py. - В стратегиях
data.historyиdata.currentвызываются сawait, у заявок обязателенstyle=MarketOrder(). - Из справочника Финама импортируются акции и фонды; фьючерсы и опционы пропускаются.
- Торговый день AlgoPack (07:00–23:50) длиннее основной сессии акций (10:00–18:45), поэтому
volиpr_closeвключают утро и вечер. - С версии 1.26.10.1 zipFinam подключается к ziplime через точки расширения (entry points
ziplime.venue_calendarsиziplime.address_schemes): площадки Мосбиржи, календарь FORTS и адресаalgopack://работают, как только пакет установлен,import zipfinamдля этого не нужен. Прежняя подменаTradingAlgorithm._resolve_named_data_sourceубрана.
GNU GPL v3, как у ziplime.