Торговый алгоритм на Python для IB.API: Contracts

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



Что это Contract?

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

Контракт — это специальный объект IBApi.Contract. Он содержит в себе информацию по конкретному торговому инструменту. Используя эту информацию, TWS выбирает отдельный торговый инструмент и проводит с ним операции, которые мы запросили.

Для чего нужны контракты?

Разумеется для запросов TWS. Контракты применяются в запросах, где используется определенный торговый инструмент. Чаще всего — это запрос исторических данных, получение текущих котировок, отправка ордера (изменение или отмена).

Из чего состоит контракт?

Так как контракт — это отдельный класс Python. После создания объекта необходимо назначить его свойства, которые будут понятны TWS. Обязательные свойства, которые необходимы:

  • Symbol — тикер актива.
  • Security type — тип актива.
  • Currency — валюта.
  • Exchange — биржа.

Где взять свойства контракта?

Лучший способ понять, как заполнить нужные свойства контракта —  это посмотреть в самом TWS.

Откройте TWS. В окне Watchlist (если этого окна нет, откройте его через File -> New Window -> Watchlist) выберите интересующий вас торговый инструмент,  нажмите на нём правой кнопкой мыши и в появившемся окне выберите Financial Instrument Info -> Description. Если этого пункта не нашли, то нажмите на значок стрелки внизу меню.

Должно появиться вот такое окно:

Здесь будут видны необходимые данные.

Какие контракты существуют?

Interactive Brokers предоставляет возможность торговать огромным количеством торговых инструментов. Чтобы «дотянуться» до них с помощью своего алгоритма, вы должны понимать, какие типы контрактов возможны и доступны.

Все контракты делятся на две большие группы:

В данной статье мы не будем подробно расписывать каждую группу контрактов, дабы не «раздуть» статью до масштабов энциклопедии. Но вы можете самостоятельно почитать про них по ссылкам выше.

Переходим к работе с кодом

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

Для создания контракта и дальнейшей работы с ним нам потребуется:

# импортировать модуль с классом Contract
import ibapi.contract

# создать объект класса Contract
contract1 = ibapi.contract.Contract()         # Это будет пример 1 - валютная пара FX
contract2 = ibapi.contract.Contract()         # Это будет пример 2 - акция

# Заполнить атрибуты объекта минимальными данными

contract1.symbol = "EUR"                       # Контракт на валютную пару EUR.GBP
contract1.secType = "CASH"                     
contract1.currency = "GBP"
contract1.exchange = "IDEALPRO"

contract2.symbol = "IBKR"                      # Контракт на акцию Interactive Brokers
contract2.secType = "STK"                     
contract2.currency = "USD"
contract2.exchange = "ISLAND"                  # В API, биржа NASDAQ всегда определяется как ISLAND в поле exchange

В «боевых» алгоритмах на этом работа с контрактом будет завершена. Далее созданный объект надо будет передавать в необходимый метод, где необходим контракт.

Но в рамках данной статьи, мы продолжим работу с контрактом и напишем алгоритм, который запросит все параметры созданного нами контракта.

Код в студию!

Все детали по созданному контракту запрашиваются у TWS через метод IBApi.EClient.reqContractDetails(). А ответ от TWS возвращается в метод IBApi.EWrapper.contractDetails() и IBApi.EWrapper.contractDetailsEnd().

Следовательно мы создадим свой класс, который будет наследоваться от EWrapper, и перепишем в нем соответствующие методы.

# Импортируем необходимые библиотеки
import ibapi.wrapper
import ibapi.client
import ibapi.contract                                       # Contract - интересующий сейчас класс
import threading
import time                                                 # модуль времени из стандартной библ-ки Python

# Класс-наследник EWrapper
class MyWrapper(ibapi.wrapper.EWrapper):
    # Добавлен инициализатор объекта
    def __init__(self):
        self.nvid = 0                                       # переменная для next valid order id
        self.con_detail_recive = False                      # Флаг для полученного контракта
    
    # Переписан базовый метод .nextValidId()
    def nextValidId(self, orderId:int):
        super().nextValidId(orderId)
        self.nvid = orderId                                 # записываем значение next valid order id
        
    # Метод, который принимает ответ на запрос деталей контракта
    def contractDetails(self, reqId:int, contractDetails: ibapi.contract.ContractDetails):
        # Выводим все параметры объекта и их значения
        for arg in dir(contractDetails):                    # Обходим все атрибуты объекта contractDetails
            if not arg.startswith('_'):                     # Исключаем приватные атрибуты
                val = getattr(contractDetails, arg)         # Значение конкретного атрибута
                print ("{} = {}".format(arg, val))          # Печатаем атрибут и его значение
    
    # Метод, завершающий прием ответа на запрос деталей контракта
    def contractDetailsEnd(self, reqId:int):
        self.con_detail_recive = True
        print("Закончили принимать параметры контракта")    # Печатаем статус

# Создаем необходимые объекты
tws = ibapi.client.EClient(MyWrapper())                     # Объект класса Eclient
cnt = ibapi.contract.Contract()                             # Объект класса Contract

# Контракт на валютную пару EUR.USD
cnt.symbol = "EUR"
cnt.secType = "CASH"
cnt.currency = "USD"
cnt.exchange = "IDEALPRO"



tws.connect("127.0.0.1", 7496, 1)                           # подключаемся к терминалу

if tws.isConnected():                                       # В случе успешного подключения к TWS
    th = threading.Thread(target=tws.run)                   # Организовываем поток
    th.start()                                              # Запускаем потоки
    
    while tws.wrapper.nvid == 0:                            # Пока TWS не прислал Next Valid ID
        time.sleep(.5)                                      # Спим полсекунды
    
    tws.reqContractDetails(tws.wrapper.nvid, cnt)           # Запрашиваем все необходимые данные по контракту
    while not tws.wrapper.con_detail_recive:                # Ждем получение ...
        time.sleep(.2)                                      # ... деталей контракта
    
    tws.done = True                                         # Переводим флаг отключения
    while tws.done:                                         # Ждем пока произойдет ...
        time.sleep(.2)                                      # ... отключение от TWS
    
    print("----- !!!THE END!!! -----")

Обратите внимание на переписанный метод MyWrapper.contractDetails(). После запроса деталей контракта TWS присылает в него объект contractDetails: ibapi.contract.ContractDetails. Суть метода сводится к тому, чтобы пройтись по всем свойствам данного объекта и вывести их на экран.

Для чего? В целях демонстрации всех полей указанного нами контракта. Возможно при ваших экспериментах вам понадобится что-то из этих данных. Я же, со своей стороны, хочу обратить ваше внимание на такое свойство, как orderTypes. В следующих статьях нам  оно пригодится.

Так же обратите внимание на свойство класса MyWrapper.con_detail_recive. Его я ввел в код специально, чтобы отследить, когда контракт будет получен. В своих алгоритмах вы можете его не применять.

Заключение

Контракты — ключевой объект Python, так как участвует в важнейших операциях с TWS (запрос котировок, запрос истории, отправка торговых приказов).

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

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