Metadata-Version: 2.5
Name: zipfinam
Version: 1.26.10.1
Summary: Бэктест и алготорговля на Мосбирже через Финам. Надстройка над ziplime.
Project-URL: Homepage, https://github.com/arbuzovv/zipFinam
Project-URL: Ziplime, https://github.com/Limex-com/ziplime
Author: Limex
License-Expression: GPL-3.0-only
License-File: LICENSE
Keywords: algopack,backtesting,finam,moex,russia,trading,ziplime
Classifier: Natural Language :: Russian
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Office/Business :: Financial :: Investment
Requires-Python: <4.0,>=3.12
Requires-Dist: aiocache>=0.12
Requires-Dist: exchange-calendars>=4.5
Requires-Dist: googleapis-common-protos<2,>=1.72
Requires-Dist: grpcio<2,>=1.78
Requires-Dist: polars>=1.0
Requires-Dist: protobuf<7,>=6.31.1
Requires-Dist: structlog>=24
Requires-Dist: ziplime<3,>=2.11.0
Provides-Extra: ai
Requires-Dist: numpy>=1.24; extra == 'ai'
Requires-Dist: openai>=1.30; extra == 'ai'
Requires-Dist: python-dotenv>=1.0; extra == 'ai'
Requires-Dist: quantstats>=0.0.62; extra == 'ai'
Requires-Dist: rich>=13; extra == 'ai'
Provides-Extra: algopack
Requires-Dist: moexalgo==2.5.12; extra == 'algopack'
Provides-Extra: all
Requires-Dist: aiohttp>=3.9; extra == 'all'
Requires-Dist: finam-trade-api<5,>=4.4; extra == 'all'
Requires-Dist: httpx>=0.27; extra == 'all'
Requires-Dist: moexalgo==2.5.12; extra == 'all'
Requires-Dist: numpy>=1.24; extra == 'all'
Requires-Dist: openai>=1.30; extra == 'all'
Requires-Dist: python-dotenv>=1.0; extra == 'all'
Requires-Dist: quantstats>=0.0.62; extra == 'all'
Requires-Dist: rich>=13; extra == 'all'
Provides-Extra: dev
Requires-Dist: aiohttp>=3.9; extra == 'dev'
Requires-Dist: finam-trade-api<5,>=4.4; extra == 'dev'
Requires-Dist: httpx>=0.27; extra == 'dev'
Requires-Dist: moexalgo==2.5.12; extra == 'dev'
Requires-Dist: numpy>=1.24; extra == 'dev'
Requires-Dist: openai>=1.30; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: python-dotenv>=1.0; extra == 'dev'
Requires-Dist: quantstats>=0.0.62; extra == 'dev'
Requires-Dist: rich>=13; extra == 'dev'
Provides-Extra: live
Requires-Dist: aiohttp>=3.9; extra == 'live'
Requires-Dist: finam-trade-api<5,>=4.4; extra == 'live'
Requires-Dist: httpx>=0.27; extra == 'live'
Description-Content-Type: text/markdown

<p align="center">
  <picture>
    <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/arbuzovv/zipFinam/main/img/zipfinam-demo-dark.gif">
    <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/arbuzovv/zipFinam/main/img/zipfinam-demo-light.gif">
    <img src="https://raw.githubusercontent.com/arbuzovv/zipFinam/main/img/zipfinam-demo-light.gif" width="100%" alt="zipFinam: бэктест и алготорговля на Мосбирже через Финам">
  </picture>
</p>

<h1 align="center">zipFinam <br> Бэктест и алготорговля на Мосбирже через Финам.</h1>

<p align="center">
  <b>zipFinam — открытая Python-библиотека для бэктеста и алготорговли на Московской бирже:<br>
  котировки Финама, торговые календари MOEX и исполнение заявок через Finam Trade API.</b><br><br>
  Стратегия, проверенная на истории, без переписывания запускается на вашем счёте в Финаме.
</p>

<p align="center">
  <a href="https://pypi.org/project/zipfinam/"><img src="https://img.shields.io/pypi/v/zipfinam" alt="PyPI"></a>
  <a href="https://pypi.org/project/zipfinam/"><img src="https://img.shields.io/pypi/pyversions/zipfinam" alt="Python"></a>
  <a href="#license"><img src="https://img.shields.io/github/license/arbuzovv/zipFinam" alt="License"></a>
  <a href="https://github.com/arbuzovv/zipFinam"><img src="https://img.shields.io/github/stars/arbuzovv/zipFinam.svg?style=social&label=Star" alt="Stars"></a>
</p>

<p align="center">
  <a href="#why">Зачем это нужно</a> ·
  <a href="#finam-data">Котировки Финама</a> ·
  <a href="#algopack">MOEX AlgoPack</a> ·
  <a href="#live">Торговля на своём счёте</a> ·
  <a href="#quick-start">Начало работы</a> ·
  <a href="#license">Лицензия</a>
</p>

<p align="center">
  акции и фонды MOEX из Финам Trade API · календари MOEX и FORTS · заявки целыми лотами ·
  капитал стратегии, а не весь счёт · данные MOEX AlgoPack по желанию · движок ziplime
</p>

---

<a id="why"></a>
## Зачем это нужно

Большинство инструментов для бэктеста сделаны для американского рынка. На Мосбирже с ними
начинаются проблемы:

- **Нет данных.** Популярные бесплатные источники вроде `yfinance` российские бумаги толком не
  покрывают.
- **Свечей мало.** OHLCV показывает, *куда* сходила цена, но не *кто* её двигал: агрессивный
  покупатель или пустой стакан, толпа или один крупный игрок.
- **Тестер заглядывает в будущее.** Биржевая статистика публикуется с задержкой, иногда
  пересчитывается задним числом, и наивный бэктест незаметно читает то, чего в тот момент ещё не
  было.
- **От теста до торговли — вторая разработка.** Стратегию, проверенную в одном инструменте,
  приходится переписывать под API брокера.

zipFinam закрывает все четыре проблемы.

---

<a id="finam-data"></a>
## 📈 Котировки Финама — вся Мосбиржа одной командой

Бары и справочник инструментов приходят напрямую из **Финам Trade API**: акции и фонды MOEX,
таймфреймы от минуты до квартала. Нужен только токен из личного кабинета Финама.

```bash
cd examples
python ingest_finam.py      # справочник инструментов и дневные бары
python run_backtest.py      # бэктест на голубых фишках
```

Финам подключается к движку как штатный провайдер данных: `get_market_data_source("finam")`
работает так же, как встроенный Yahoo для американского рынка.

---

<a id="algopack"></a>
## 🔬 MOEX AlgoPack — то, чего не видно в свечах

[AlgoPack](https://data.moex.com) — аналитика, которую Мосбиржа считает по собственной ленте
сделок и стакану. Их не восстановить по свечам или ленте: биржа видит каждую заявку, включая снятые.
В zipFinam таблицы AlgoPack читаются той же строкой, что и цены:

```python
# 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/`](https://github.com/arbuzovv/zipFinam/tree/main/examples/algorithms/algopack) по стратегии на каждую таблицу:

| Стратегия | Идея |
|---|---|
| `flow_tilt` | Держать голубые фишки, которые покупают агрессивные деньги |
| `orderstats_conviction` | Покупать там, где выставленные биды не снимают |
| `obstats_liquidity` | Держать то, что поддерживает стакан, а не случайный принт ленты |
| `hi2_crowding` | Идти за бумагами, где покупает кто-то один против рассеянного рынка |
| `futoi_crowd` | Стоять против толпы физлиц во фьючерсе на доллар/рубль |

```bash
python run_backtest.py algorithms/algopack/flow_tilt.py
```

---

<a id="live"></a>
## 💼 От бэктеста к вашему счёту

Та же стратегия, без изменений, торгует на вашем брокерском счёте в Финаме через Trade API.
Укажите данные счёта и запустите пример:

```bash
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 штук). Если размер лота неизвестен,
  заявка не отправляется вовсе: наугад ничего не торгуется.
- **Принятая заявка ≠ исполненная.** После каждого тика статус заявок запрашивается у брокера, и
  отклонённая заявка отмечается как ошибка, а не как успех.

---

<a id="quick-start"></a>
## Начало работы

```bash
pip install "zipfinam[all]"
```

Создайте `.env` в рабочей папке:

```env
GRPC_TOKEN=...          # токен Финам Trade API: котировки, справочник, лоты
ALGOPACK_API=...        # ключ MOEX AlgoPack, подписка на https://data.moex.com
```

Для бэктестов на свечах хватит `GRPC_TOKEN`. Можно поставить не всё:

| Extra | Что добавляет |
|---|---|
| — | Данные Финама, календари, адреса `algopack://` |
| `algopack` | Клиент MOEX AlgoPack |
| `live` | Исполнение заявок через Финам |

Стратегия — обычный Python:

```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](https://github.com/Limex-com/ziplime), открытым движком
бэктестинга и живой торговли от Limex. Движок, метрики и модели исполнения берутся из ziplime,
а zipFinam добавляет российский рынок: данные, календари и брокера.

```
zipfinam/
├── finam/               # Финам: бары, справочник, исполнение (REST и gRPC)
├── algopack/            # MOEX AlgoPack: каталог таблиц, клиент, источник данных
└── venue_calendars.py   # календарь FORTS и площадки Мосбиржи для ziplime
examples/                # загрузка, бэктест, живая торговля, стратегии
```

Тесты работают без сети: `pip install -e ".[dev]" && pytest`.

<details>
<summary>Переход с версии 0.x и ограничения</summary>

- Нужен 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` убрана.

</details>

<a id="license"></a>
## Лицензия

GNU GPL v3, как у ziplime.
