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`
Обновляет график.