File modules.md of Package fint-bot

# Модули проекта Tinkoff Invest Trade Robot

## Начало работы

Tinkoff Invest Trade Robot - это робот для алгоритмической торговли на бирже Тинькофф Инвестиций посредством Tinkoff Invest API.

### Функциональные возможности

* Автоматическая торговля любыми ценными бумагами
* Реализация собственного торгового алгоритма
* Выставление и отмена как рыночных, так и лимитных торговых поручений
* Ведение статистики, выдача краткого результата
* Логирование всех операций, возможность установки уровня логирования
* Подключение визуализации

### Запуск робота

1. Установите зависимости `python3.10 -m pip install -r requrements.txt`;
2. Получите токен и сохраните его и ID аккаунта в переменные окружения TINKOFF_TOKEN и TINKOFF_ACCOUNT соответственно;
3. Запустите файл [main.py](main.py) `python3.10 main.py`.

### Торговая стратегия

В качестве демонстрации представлена одна торговая стратегия, основанная на индикаторе двух скользящих средних.
Строятся линии двух скользящих средних, короткого и длинного. Интервалы задаются в параметрах стратегии.
При пересечении линий считается, что тренд цены меняется, и нужно либо покупать (в случае, если короткое среднее выше
длинного), либо продавать (в обратном случае).

### Архитектура проекта

Здесь находится короткое описание архитектуры. Более подробно можно прочитать на странице каждого из модулей.

#### `robotlib/robot.py`

##### `TradeRobotFactory` - фабрика роботов

Получает из API параметры ценной бумаги и аккаунта, и используя их создает робота.

##### `TradeRobot` - торговый робот

Выступает в роли прокси между API Тинькофф Инвестиций и торговой стратегией.

При запуске метода `trade()` загружает исторические данные, сохраняет их в торговую стратегию,
подписывается на bidirectional-stream необходимой для стратегии биржевой информации. При получении обновлений,
передает их в стратегию, дожидается от нее решения по дальнейшим действиям и исполняет их.

Вся статистика торговых поручений робота записывается в объект типа `TradeStatisticsAnalyzer` и возвращается в конце работы
для дальнейшего анализа или сохранения. Также может быть получена в любой момент из `robot.trade_statistics`.

В зависимости от режима работы, выставленного в параметрах робота, он может торговать как в песочнице, так и на бирже.

Также робот имеет функцию бэктеста стратегии `backtest()`.

#### `robotlib/stats.py`

##### `TradeStatisticsAnalyzer` - статистика робота

Используется для записи, хранения и получения статистики, а также генерации отчетов и коротких сводок. Ведение статистики
полностью ведется роботом, пользователю рекомендуется использовать только функции сохранения в файл и генерации
отчетов.

Для сохранения и чтения из файла есть методы `save_to_file(filename)` и `read_from_file(filename)` соответственно.

Для генерации отчета используется метод `get_report(processors, calculators)`. Пользователям предоставляется возможность
кастомизации отчетов посредством передачи в метод списка процессоров и калькуляторов.

##### `TradeStatisticsProcessorBase`

**Процессоры** должны быть унаследованы от этого класса. Они позволяют преобразовывать таблицу итогового отчета
(например, добавлять столбцы с подсчетом параметров, преобразовывать типы данных и т.д.). Для этого в них необходимо
переопределить метод `process(df)`.

Пример реализованного процессора: `BalanceProcessor`.

##### `BalanceCalculator`

**Калькуляторы** должны быть унаследованы от этого класса. Они позволяют строить из отчета короткую сводку с важными
показателями (например, максимальная потеря за время торгов, итоговый заработок и т.д.). Для этого в них необходимо
переопределить метод `calculate(df)`.

Пример реализованного калькулятора: `BalanceCalculator`.

#### `robotlib/strategy.py`

##### `TradeStrategyBase`

Абстрактный класс (интерфейс) торговой стратегии. Он обрабатывает обновления данных, предоставляемые роботом и
возвращает результат - торговое поручение, которое необходимо реализовать роботу, или список тех, которые надо отменить.
Для этого используется метод `decide(market_data, params)`.

Бэктест стратегии работает аналогичным образом, за исключением того, что в нем предоставляются только данные свечей. Для
него необходимо реализовать метод `decide_by_candle(candle, params)`.

Примеры реализованной стратегии: `RandomStrategy`, `MAEStrategy`.

#### `robotlib/money.py`

Содержит вспомогательный класс `Money`. Он полностью аналогичен классу `Quotation` из API Тинькофф Инвестиций, но
с реализованными операторами сложения, вычитания и умножения на число, а также методы преобразования в / из `int`,
`float`, `tinkoff.invest.Quotation`, `tinkoff.invest.MoneyValue`.

#### `rootlib/visualization.py`

Позволяет подключить наглядную визуализацию курса ценной бумаги, а так же
покупок и продаж робота в произвольную стратегию. Для этого необходимо создать
объект класса `Visualizer`, после чего добавлять в него все обновления цены
методом `add_price(time, price)`, покупки и продажи методами `add_buy(time)`,
`add_sell(time)` соответственно.

## Модуль money

Содержит класс `Money`, используемый для точного хранения роботом денежных типов данных. Устроен аналогично
классам `Quotation` и `MoneyValue` в [Tinkoff Invest API](https://tinkoff.github.io/investAPI/faq_custom_types/#quotation),
вдобавок в нем реализованы методы преобразования в/из int, float, Quotation, MoneyValue, а также операторы сложения,
вычитания, умножения на число.

### Money

#### Методы

##### `__init__`

*Входные данные*:

| Field | Type                                 | Description                                                 |
|-------|--------------------------------------|-------------------------------------------------------------|
| value | int / float / Quotation / MoneyValue | Значение                                                    |
| nano  | Optional[int]                        | Значение nano (при использовании необходимо value типа int) |

*Выходные данные*: Money.

##### `to_float`

Преобразовывает значение в float.

##### `to_quotation`

Преобразовывает значение в Quotation.

##### `to_money_value`

Преобразовывает значение в MoneyValue.

*Входные данные*:

| Field    | Type | Description                                     |
|----------|------|-------------------------------------------------|
| currency | str  | Валюта, в которой необходимо вернуть MoneyValue |

*Выходные данные*: MoneyValue.

#### Примеры использования

```python
from tinkoff.invest import Quotation
from robotlib.money import Money
q = Quotation(units=1600, nano=250000000)
money_1 = Money(57.25)
money_2 = Money(1000)

money = Money(q) + money_1 + money_2
print(money)
# output: <Money units=2657 nano=500000000>
## Модуль robot

Содержит классы, непосредственно связанные с торговым роботом:

* `TradingRobot` - торговый робот;
* `TradingRobotFactory` - фабрика торговых роботов, позволяет просто создавать робота.

**Внимание!** Рекомендуется не создавать робота вручную, а использовать для этого фабрику, так как фабрика умеет
получать сведения об аккаунте и инструменте непосредственно из API, и не требует передачи этих данных в конструктор.
При необходимости точечной настройки робота (например, ограничение баланса, доступного для траты) возможно
отредактировать параметры робота после его создания.

На текущий момент один робот ограничен одним аккаунтом и одним видом ценных бумаг. При желании настроить торговлю
одновременно несколькими бумагами и / или с нескольких аккаунтов, рекомендуется создать и параллельно запустить
нескольких роботов.

### TradingRobot

Основной класс, торговый робот. Содержит в себе всю логику взаимодействия с API: создание и отмена торговых поручений,
подписка на обновления и т.д.

#### Методы

##### `__init__`

*Входные данные*:

| Field            | Type                      | Description                                                     |
|------------------|---------------------------|-----------------------------------------------------------------|
| token            | str                       | Токен API Тинькофф Инвестиций                                   |
| account_id       | str                       | ID аккаунта, с которого будет вестись торговля.                 |
| sandbox_mode     | bool                      | True для запуска робота в песочнице, False для "боевого" режима |
| trade_strategy   | TradeStrategyBase         | Стратегия торгового робота                                      |
| trade_statistics | TradeStatisticsAnalyzer   | Анализатор статистики робота                                    |
| instrument_info  | tinkoff.invest.Instrument | Информация о торгуемых ценных бумагах                           |
| logger           | logging.Logger            | Логгер                                                          |

*Выходные данные*: `TradingRobot`.

##### `trade`

Запуск торгового алгоритма.

Метод загружает в стратегию исторические данные и подписывается на необходимые обновления биржевых данных.
При получении обновления, передает его стратегии и действует согласно ее распоряжению.

*Выходные данные*: `TradeStatisticsAnalyzer` - статистика робота.

##### `backtest`

Тестирование торговой стратегии на исторических данных.

Метод получает из API данные за два последовательных периода длиной `train_duration` и `test_duration`.
Обучающие данные загружает в робота в качестве исторических данных, после чего последовательно передает ему
тестовые данные в качестве текущих биржевых данных. Все торговые поручения стратегии записывает в статистику,
предоставляемую на выходе для анализа.

*Входные данные*:

| Field            | Type                      | Description                              |
|------------------|---------------------------|------------------------------------------|
| initial_params   | TradeStrategyParams       | Изначальные параметры торговой стратегии |
| test_duration    | datetime.timedelta        | Длительность тестового периода           |
| train_duration   | datetime.timedelta        | Длительность обучающего периода          |

*Выходные данные*: `TradeStatisticsAnalyzer` - статистика робота.

##### `to_money_value`

Преобразовывает значение в MoneyValue.

*Входные данные*:

| Field    | Type | Description                                     |
|----------|------|-------------------------------------------------|
| currency | str  | Валюта, в которой необходимо вернуть MoneyValue |

*Выходные данные*: MoneyValue.

### TradingRobotFactory

Фабрика торговых роботов.

#### Методы

##### `__init__`

Во входных данных обязательно должны быть представлены либо `figi`, либо `ticker` и `class_code`.

*Входные данные*:

| Field        | Type          | Description                                     |
|--------------|---------------|-------------------------------------------------|
| token        | str           | Токен API Тинькофф Инвестиций                   |
| account_id   | str           | ID аккаунта, с которого будет вестись торговля. |
| figi         | Optional[str] | FIGI торгового инструмента                      |
| ticker       | Optional[str] | Тикер торгового инструмента                     |
| class_code   | Optional[str] | class_code торгового инструмента                |
| logger_level | Optional[str] | Уровень логирования. По умолчанию INFO          |

*Выходные данные*: `TradingRobotFactory`.

##### `setup_logger`

Настройка логгера.

*Входные данные*:

| Field        | Type | Description         |
|--------------|------|---------------------|
| logger_level | str  | Уровень логирования |

*Выходные данные*: `logging.Logger`.

##### `create_robot`

Создание торгового робота для инструмента, указанного в параметрах фабрики.

*Входные данные*:

| Field          | Type              | Description                                         |
|----------------|-------------------|-----------------------------------------------------|
| trade_strategy | TradeStrategyBase | Торговая стратегия                                  |
| sandbox_mode   | bool              | Режим торговли (True - песочница, False - "боевой") |

*Выходные данные*: `TradingRobot`.

#### Примеры использования

См. файл [main.py](https://github.com/karpp/investRobot/blob/master/main.py).
## Модуль stats

Содержит классы для ведения статистики торгового робота.

### TradeStatisticsAnalyzer

Основной класс, используемый для записи, хранения и получения статистики, а также генерации отчетов и коротких сводок.

Класс предоставляет возможность преобразовать формат отчета, а также сгенерировать короткую сводку. Для этого необходимо
реализовать классы, унаследованные от `TradeStatisticsProcessorBase` и `TradeStatisticsCalculatorBase` соответственно
и передать объекты этих классов в параметры функции `get_report`.

#### Методы

##### `__init__`

*Входные данные*:

| Field           | Type                      | Description                                                 |
|-----------------|---------------------------|-------------------------------------------------------------|
| positions       | int                       | Значение                                                    |
| money           | float                     | Значение nano (при использовании необходимо value типа int) |
| instrument_info | tinkoff.invest.Instrument | Информация об инструменте тоговли                           |
| logger          | logging.Logger            | Логгер                                                      |

*Выходные данные*: `TradeStatisticsAnalyzer`.

##### `add_trade`

Запись операции в статистику. Этот метод в основном используется роботом, **не рекомендуется** вызывать его самостоятельно.

*Входные данные*:

| Field | Type                      | Description |
|-------|---------------------------|-------------|
| trade | tinkoff.invest.OrderState | Операция    |

##### `cancel_order`

Отмена операции, удаление из статистики. Этот метод в основном используется роботом, **не рекомендуется** вызывать его самостоятельно.

*Входные данные*:

| Field    | Type | Description |
|----------|------|-------------|
| order_id | int  | ID операции |

##### `get_positions`

Получение количества ценных бумаг на счету на текущий момент.

*Выходные данные*: `int`, количество бумаг.

##### `get_money`

Получение баланса на текущий момент.

*Выходные данные*: `float`, баланс.

##### `get_pending_orders`

Получение списка нереализованных торговых заявок.

*Выходные данные*: `list[tinkoff.invest.OrderState]`, список заявок.

##### `save_to_file`

Сохранение статистики в файл.

*Входные данные*:

| Field    | Type | Description    |
|----------|------|----------------|
| filename | str  | Название файла |

##### `load_from_file`

Чтение статистики из файла.

*Входные данные*:

| Field    | Type | Description    |
|----------|------|----------------|
| filename | str  | Название файла |

*Выходные данные*: `TradeStatisticsAnalyzer`

##### `add_backtest_trade`

Запись в статистику операции из бэктеста.

*Входные данные*:

| Field     | Type                          | Description        |
|-----------|-------------------------------|--------------------|
| quantity  | int                           | Количество лотов   |
| price     | Quotation                     | Цена лота          |
| direction | tinkoff.invest.OrderDirection | Направление сделки |

##### `get_report`

Получение отчета о статистике.

Метод собирает датафрейм с полной статистикой об операциях, после чего последовательно
запускает на нем пользовательские обработчики. Для получения краткого отчета запускаются пользовательские генераторы
краткой сводки, и их результаты объединяются в один dict.

*Входные данные*:

| Field       | Type                                | Description               |
|-------------|-------------------------------------|---------------------------|
| processors  | list[TradeStatisticsProcessorBase]  | Обработчики статистики    |
| calculators | list[TradeStatisticsCalculatorBase] | Генераторы краткой сводки |

*Выходные данные*: `dict[str, any], pandas.DataFrame`: словарь с краткой сводкой, полная статистика по операциям.

#### Примеры использования

##### Генерация отчета

```python
import pandas as pd
from robotlib.stats import TradeStatisticsAnalyzer, TradeStatisticsProcessorBase, TradeStatisticsCalculatorBase

class BalanceProcessor(TradeStatisticsProcessorBase):
    def process(self, df: pd.DataFrame) -> pd.DataFrame:
        df['balance'] = -(df['total_order_amount'] * df['sign']).cumsum()
        df['instrument_balance'] = (df['lots_executed'] * df['sign']).cumsum()
        return df

    
class BalanceCalculator(TradeStatisticsCalculatorBase):
    def calculate(self, df: pd.DataFrame) -> dict[str, any]:
        final_balance = df['balance'][len(df) - 1]
        final_instrument_balance = df['instrument_balance'][len(df) - 1]
        final_price = df['average_position_price'][len(df) - 1]
        return {
            'final_balance': final_balance,
            'max_loss': -df['balance'].min(),
            'final_instrument_balance': final_instrument_balance,
            'income': final_balance + final_instrument_balance * final_price  # todo: * instrument_info.lot
        }

    
stats: TradeStatisticsAnalyzer
# предположим, что эта статистика уже содержит данные

short_summary, full_report = stats.get_report(processors=[BalanceProcessor()], calculators=[BalanceCalculator()])

print(short_summary)
# output: {'final_balance': -1764.8, 'max_loss': 1889.2, 'final_instrument_balance': 1, 'income': -177.39999999999986}
print(full_report)
# output: dataframe with all the trades
TradeStatisticsProcessorBase
#### Методы

##### `process`

Преобразования отчета

*Входные данные*:

| Field | Type             | Description  |
|-------|------------------|--------------|
| df    | pandas.DataFrame | Полный отчет |

*Выходные данные*: `pandas.DataFrame`: преобразованный отчет.

### TradeStatisticsCalculatorBase

Интерфейс, который необходимо реализовать для преобразования краткой сводки.

#### Методы

##### `calculate`

*Входные данные*:

| Field | Type             | Description  |
|-------|------------------|--------------|
| df    | pandas.DataFrame | Полный отчет |

*Выходные данные*: `dict[str, any]`: словарь ключ-значение, содержащий краткую сводку.
Этот фрагмент уже присутствует в модуле stats, который мы отправили ранее. Если нужно добавить его в другое место или переупорядочить, уточните, пожалуйста.

markdown
### TradeStatisticsProcessorBase

Интерфейс, который необходимо реализовать при необходимости преобразования отчета.

#### Методы

##### `process`

Преобразования отчета.

*Входные данные*:

| Field | Type             | Description  |
|-------|------------------|--------------|
| df    | pandas.DataFrame | Полный отчет |

*Выходные данные*: `pandas.DataFrame` - преобразованный отчет.

### TradeStatisticsCalculatorBase

Интерфейс, который необходимо реализовать для преобразования краткой сводки.

#### Методы

##### `calculate`

Генерация краткой сводки на основе отчета.

*Входные данные*:

| Field | Type             | Description  |
|-------|------------------|--------------|
| df    | pandas.DataFrame | Полный отчет |

*Выходные данные*: `dict[str, any]` - словарь ключ-значение, содержащий краткую сводку.

## Модуль strategy

Содержит классы стратегии торгового робота.

### TradeStrategyBase

Интерфейс стратегии торгового робота. Содержит в себе логику обработки обновлений биржевых данных.
Пользователь может использовать одну из представленных реализаций
(`RandomStrategy`, `MAEStrategy`) или реализовать собственную.

Торговый робот использует [bidirectional-stream](https://tinkoff.github.io/investAPI/head-marketdata/#bidirectional-stream)
Тинькофф Инвестиций для получения информации о событиях. Для настройки событий, на которые стратегии необходима подписка
следует использовать параметры стратегии `candle_subscription_interval`, `order_book_subscription_depth`, `trades_subscription`

#### Представленные реализации

##### `RandomStrategy` - Случайная стратегия

С каждым обновлением данных принимает решение о покупке / продаже рандомного числа лотов исходя из параметров, имеющихся
лотов и баланса. Не имеет потенциала, может использоваться для тестирования и в качестве примера стратегии.

##### `MAEStrategy` - Стратегия скользящего среднего

Данная стратегия основана на индикаторе скользящей средней.
Раз в минуту (при получении новой минутной свечи) рассчитывает два скользящих средних, длины которого можно задать
в конструкторе.
При изменении знака их разницы (пересечении линии скользящих средних) считает,
что текущий тренд цены изменился и отдает распоряжение на покупку / продажу, если "короткое" среднее выше или ниже
"длинного" соответственно. Покупает и продает каждый раз фиксированное число, изначально заданное в конструкторе,
при условии, что это возможно.

#### Свойства

| Field                         | Type                                         | Description                          |
|-------------------------------|----------------------------------------------|--------------------------------------|
| candle_subscription_interval  | tinkoff.invest.SubscriptionInterval          | Период свечей для подписки           |
| order_book_subscription_depth | Optional[int]                                | Глубина стакана для подписки         |
| trades_subscription           | bool                                         | Подписка на обезличенные операции    |
| strategy_id                   | str                                          | id стратегии (используется логгером) |

#### Методы

##### `load_instrument_info`

Запись информации об инструменте. Метод вызывается классом `TradeRobotFabric`.

*Входные данные*:

| Field           | Type                      | Description               |
|-----------------|---------------------------|---------------------------|
| instrument_info | tinkoff.invest.Instrument | Информация об инструменте |

##### `load_candles`

Загрузка исторических свечей. Вызывается роботом при начале торгов. Может быть переопределена пользователем для
настройки параметров стратегии.

*Входные данные*:

| Field   | Type                                | Description                |
|---------|-------------------------------------|----------------------------|
| candles | list[tinkoff.invest.HistoricCandle] | Список исторических свечей |

##### `decide`

Данный метод вызывается при получении новых биржевых данных. Возвращает объект, содержащий поручения торговому роботу.

*Входные данные*:

| Field       | Type                                        | Description              |
|-------------|---------------------------------------------|--------------------------|
| market_data | tinkoff.invest.MarketDataResponse           | Биржевые данные          |
| params      | TradeStrategyParams                         | Текущие параметры робота |

*Выходные данные*: StrategyDecision - решения о действиях торгового робота.

##### `decide_by_candle`

Данный метод аналогичен методу decide, однако у него входные данные содержат только обновления свечей. Данный метод
необходим для бэктеста стратегии, так как получение исторических данных по стаканам и обезличенным операциям не
предоставляется возможным.

*Входные данные*:

| Field  | Type                        | Description              |
|--------|-----------------------------|--------------------------|
| candle | tinkoff.invest.MarketDataResponse | Свеча                    |
| params | TradeStrategyParams         | Текущие параметры робота |

*Выходные данные*: StrategyDecision - решения о действиях торгового робота.

### Структуры данных

#### TradeStrategyParams

Структура данных, передаваемая на вход стратегии при обновлении данных.

| Field              | Type                            | Description                            |
|--------------------|---------------------------------|----------------------------------------|
| instrument_balance | int                             | Количество лотов инструмента на счету  |
| currency_balance   | float                           | Баланс счета                           |
| pending_orders     | list[tinkoff.invest.OrderState] | Список нереализованных биржевых заявок |

#### RobotTradeOrder

Структура данных, содержащая получение торговому роботу на выставление рыночной заявки.

| Field      | Type                          | Description                                  |
|------------|-------------------------------|----------------------------------------------|
| quantity   | int                           | Количество лотов                             |
| direction  | tinkoff.invest.OrderDirection | Направление заявки (покупка / продажа)       |
| price      | Optional[Money]               | Цена заявки (при отсутствии - рыночная цена) |
| order_type | tinkoff.invest.OrderType      | Тип заявки                                   |

#### StrategyDecision

Структура данных, возвращаемая стратегией и содержащая решение о действиях торгового робота.

| Field             | Type                      | Description                                         |
|-------------------|---------------------------|-----------------------------------------------------|
| robot_trade_order | Optional[RobotTradeOrder] | Поручение роботу                                    |
| cancel_orders     | list[OrderState]          | Список биржевых заявок, которые необходимо отменить |

## Модуль visualizer

### `Visualizer`

Позволяет подключить наглядную визуализацию курса ценной бумаги, а так же
покупок и продаж робота в произвольную стратегию. Для этого необходимо создать
объект класса `Visualizer`, после чего добавлять в него все обновления цены
методом `add_price(time, price)`, покупки и продажи методами `add_buy(time)`,
`add_sell(time)` соответственно.

#### Методы

##### `__init__`

*Входные данные*:

| Field    | Type | Description |
|----------|------|-------------|
| ticker   | str  | Тикер       |
| currency | str  | Валюта      |

*Выходные данные*: `Visualizer`.

##### `add_price`

Сохраняет в визуализатор обновление цены.

*Входные данные*:

| Field | Type              | Description      |
|-------|-------------------|------------------|
| time  | datetime.datetime | Время обновления |
| price | float             | Цена             |

##### `add_buy`

Сохраняет в визуализатор покупку.

*Входные данные*:

| Field | Type              | Description      |
|-------|-------------------|------------------|
| time  | datetime.datetime | Время обновления |

##### `add_sell`

Сохраняет в визуализатор продажу.

*Входные данные*:

| Field | Type              | Description      |
|-------|-------------------|------------------|
| time  | datetime.datetime | Время обновления |

##### `update_plot`

Обновляет график.


openSUSE Build Service is sponsored by