Выставление ордеров

Общие вопросы

В этом уроке мы обсудим, как можно размещать, отслеживать, изменять и отменять торговые ордера с помощью TWS API. Чтобы продемонстрировать основные компоненты, необходимые для размещения торгового ордера, представлена простая программа Python, которая размещает торговый ордер AAPL на игровой счет, а затем выводит сообщения о статусе ордера на консоль. Представлены важные темы, связанные с размещением и мониторингом ордеров из API, включая идентификатор главного клиента, коэффициент эффективности ордера Order Efficiency Ratio (OER) и максимальную скорость сообщений API. Наконец, мы рассмотрим несколько особых случаев, в которых комиссии и сборы отличаются для ордеров API и для ордеров, созданных непосредственно в торговом приложении IBKR.

Распространенной причиной использования TWS API является размещение ордеров на счет(а) IBKR из стороннего или пользовательского программного обеспечения. Это может быть частью автоматизированной стратегии или вызвано ручным действием пользователя в графическом пользовательском интерфейсе клиента API. В этом уроке мы обсудим функцию placeOrder в классе API EClient и опишем, как она используется для размещения ордеров, а также те функции, которые используются для отслеживания состояния ордера и информации об исполнении.

Для справки: в справочном руководстве по API есть раздел, в котором описаны эти функции и приведено множество примеров определения различных типов ордеров.http://interactivebrokers.github.io/tws-api/order_submission.html

По сути, любой тип ордера, который можно разместить в TWS, также можно разместить в API. Сюда входят расширенные типы ордеров, такие как IBAlgos, скобочные ордера и условные ордера. Большинство, но не все атрибуты ордеров также можно использовать с TWS API. Как правило, атрибуты ордера должны быть установлены из API путем определения различных полей с классом ордера API, однако есть также некоторые атрибуты, которые будут считываться из предустановок в сеансе TWS или IB Gateway, к которому подключен клиент API.

Interactive Brokers предлагает более 60 типов ордеров и атрибутов и предоставляет доступ к более чем сотне бирж по всему миру. Это приводит к огромному количеству возможных комбинаций типов ордеров, инструментов и бирж. Лучший инструмент для проверки правильности определенной комбинации типа ордера, инструмента и атрибута — это сам TWS. Перед созданием сложного ордера из API рекомендуется сначала проверить, можно ли создать ордер в TWS Order Ticket. Если комбинация недействительна, как правило, TWS не отображает или выделяет недопустимый тип ордера и/или атрибут в этой комбинации.

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

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

Бумажные счета предлагаются всем владельцам счетов IBKR, а доступ к демо-счетам возможен даже до открытия реального счета.


from ibapi.client import EClient
from ibapi.wrapper import EWrapper
from ibapi.contract import Contract
from ibapi.order import *
from threading import Timer

class TestApp(EWrapper, EClient):
    def __init__(self):
        EClient.__init__(self, self)

    def error(self, reqId , errorCode, errorString):
        print("Error: ", reqId, " ", errorCode, " ", errorString)

    def nextValidId(self, orderId ):
        self.nextOrderId = orderId
        self.start()

    def orderStatus(self, orderId , status, filled, remaining, avgFillPrice, permId, parentId, lastFillPrice, clientId, whyHeld, mktCapPrice):
        print("OrderStatus. Id: ", orderId, ", Status: ", status, ", Filled: ", filled, ", Remaining: ", remaining, ", LastFillPrice: ", lastFillPrice)

    def openOrder(self, orderId, contract, order, orderState):
        print("OpenOrder. ID:", orderId, contract.symbol, contract.secType, "@", contract.exchange, ":", order.action, order.orderType, order.totalQuantity, orderState.status)

    def execDetails(self, reqId, contract, execution):
        print("ExecDetails. ", reqId, contract.symbol, contract.secType, contract.currency, execution.execId,
              execution.orderId, execution.shares, execution.lastLiquidity)

    def start(self):
        contract = Contract()
        contract.symbol = "AAPL"
        contract.secType = "STK"
        contract.exchange = "SMART"
        contract.currency = "USD"
        contract.primaryExchange = "NASDAQ"

        order = Order()
        order.action = "BUY"
        order.totalQuantity = 10
        order.orderType = "LMT"
        order.lmtPrice = 155

        self.placeOrder(self.nextOrderId, contract, order)

    def stop(self):
        self.done = True
        self.disconnect()

def main():
    app = TestApp()
    app.nextOrderId = 0
    app.connect("127.0.0.1", 7497, 9)

    Timer(3, app.stop).start()
    app.run()

if __name__ == "__main__":
    main()

Части этого примера программы для размещения ордеров покажутся вам очень знакомыми, если вы просматривали предыдущие уроки, в которых демонстрировались функции reqContractDetails, reqMktData и reqHistoricalData. В этой программе мы снова создаем класс TestApp, производный как от EClient, так и от EWrapper, но вместо этого переопределяем функции EWrapper, связанные с размещением и мониторингом ордеров, а именно: nextValidId, orderStatus, openOrder и execDetails.

Обратный вызов nextValidId используется для получения следующего действительного идентификатора заказа, который может быть использован клиентом API в этот конкретный момент для размещения нового заказа. Идентификаторы заказов, превышающие это значение, также будут приняты. Обратный вызов nextValidId вызывается в ответ на вызов API-клиентом EClient.reqIds() и, кроме того, вызывается сразу после завершения соединения в начале программы. Здесь мы демонстрируем, как лучше всего дождаться обратного вызова nextValidId, прежде чем отправлять какие-либо сообщения в TWS, в данном случае с помощью функции placeOrder. После подключения пример программы входит в цикл выполнения, который просто проверяет очередь сообщений на наличие входящих сообщений. Когда он находит сообщение для nextValidId, он вызывает этот переопределенный обратный вызов со следующим действительным идентификатором заказа в этот момент. Приложение сохраняет следующий действительный идентификатор в локальной переменной, а затем вызывает функцию start(), чтобы указать, что теперь можно отправлять исходящие сообщения.

В функции запуска здесь нам нужно определить объекты, которые передаются в качестве параметров для placeOrder. Для идентификатора заказа мы будем использовать следующий действительный идентификатор, который уже получен. Другими аргументами являются объект Contract, который однозначно определяет финансовый инструмент в базе данных IBKR, и объект Order, определяющий, как мы хотели бы разместить ордер для этого инструмента. В пример программы Program.py, который распространяется вместе с загрузкой API, входят два файла с именами ContractSamples.py и OrderSamples.py, которые содержат множество примеров определения контрактов и заказов.

Чтобы однозначно определить акции AAPL Nasdaq, здесь мы определим символ полей, тип ценной бумаги, основной обмен и валюту. Затем мы также определим поле обмена как «SMART», чтобы указать, что мы хотим SMART-маршрутизировать ордер с использованием собственного алгоритма Smart-маршрутизации IBKR. Алгоритм Smart-routing учитывает все доступные биржи, на которых торгуется ценная бумага. Для объекта «Заказ» мы решили разместить лимитный ордер, поэтому в дополнение к полям, которые почти всегда определены, или общему количеству (которое является размером ордера), действию (Купить или Продать) и типу ордера ( LMT для лимита в данном случае), нам также нужно указать лимитную цену. Важно отметить, что при определении цены заказа для акций существует минимальный шаг, который можно использовать. Например, для акций AAPL это 1 цент, поэтому цены в ордерах не могут быть указаны более чем с двумя знаками после запятой. Подробнее о нахождении минимального приращения для разных инструментов читайте в справочнике по API.

Теперь, когда у нас есть идентификатор заказа, объект Contract и объект Order, мы можем вызвать метод placeOrder. После того, как TWS получит действительный заказ, он начнет отправлять сообщения функциям обратного вызова orderStatus, openOrder и execDetails, чтобы указать статус заказа и любые изменения в статусе заказа, которые происходят. Например, в этом случае мы ожидаем увидеть для ордера AAPL LMT, размещенного в рыночные часы, обратный вызов orderStatus со статусом «Отправлен», обратный вызов openOrder с деталями ордера, а затем, возможно, обратный вызов execDetails, если заказ выполняет. Обычно будет несколько обратных вызовов orderStatus. В некоторых случаях это могут быть повторяющиеся обратные вызовы orderStatus, которые должны быть отфильтрованы клиентом API. В случае частичного заполнения будет отдельный execDetails, а также orderStatus, как правило, для каждого частичного заполнения.

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

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

  1. Клиент API может вызвать функцию reqAllOpenOrders, чтобы получить моментальный снимок информации о статусе заказа для всех заказов в учетной записи в данный момент, или,
  2. Клиент API может «связывать» заказы, у которых еще нет идентификатора заказа API, с помощью функции reqOpenOrders или reqAutoOpenOrders. Функция reqOpenOrders используется для привязки текущих ордеров, а функция reqAutoOpenOrders может использоваться для привязки ордеров, которые будут размещены в будущем. Затем связанный заказ можно отменить/изменить.
  3. С помощью параметра Master Client ID в конфигурации TWS или IB Gateway. Назначенный основной клиент будет автоматически получать обновления статуса заказа для всех открытых заказов.

Изменение ордеров

Чтобы изменить открытый ордер, клиент API должен вызвать функцию placeOrder с идентификатором ордера открытого ордера и тем же объектом контракта и объектом ордера, что и открытый ордер, за исключением измененного поля, которое необходимо изменить. Как правило, это цена заказа или размер.

Ограничения на размещение ордеров API

Для API существует ограничение скорости в 50 сообщений в секунду, которые могут быть отправлены с клиента API на TWS или IB Gateway. Это ограничение применяется только к исходящим сообщениям, а не к входящим сообщениям, отправленным клиенту API в обратном направлении. Функции в EClient, такие как placeOrder, связаны с одним исходящим сообщением, поэтому программа API может отправлять не более 50 заказов в секунду, если она не отправляет никаких других сообщений. Кроме того, важно помнить о коэффициенте эффективности заказов (OER), который отслеживает соотношение отправленных сообщений или представлений, изменений и отмен к количеству фактически выполненных заказов. В целом ожидается, что это соотношение будет около 20 или меньше, и оно будет автоматически отслеживаться серверами IBKR. Дополнительная информация по OER:  

Комиссии за заказы API

Исполнения, которые являются результатом ордеров API, в целом имеют те же комиссии, что и исполнения ордеров, размещенных любым другим способом. Единственным исключением являются прямые (в отличие от Smart-) заказы на акции США. Исполнение ордеров на акции с прямым маршрутом имеет комиссию в размере трех четвертей пенни за акцию, тогда как исполнение ордеров со смарт-маршрутизацией будет иметь комиссию в размере половины пенни за акцию в соответствии со структурой фиксированной комиссии. Кроме того, за отмену ордеров на европейские фьючерсы из API может взиматься комиссия. Более подробная информация доступна на веб-сайте.

Данные выполнения

В дополнение к информации об исполнении и комиссии, доступной в режиме реального времени для связанных подключенных клиентов API, также можно запросить выполнение в учетной записи с помощью функции reqExecutions(). Для гораздо более старых данных выполнения можно получить программный доступ с помощью веб-службы Flex или с помощью операторов в «Управлении учетными записями».

Можно переходить к следующему примеру.    Опционная доска