Как написать простую стратегию

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

Сначала научимся ставить заявку. Для этого используем метод:

C++
Python
bool add_limit_order(Dir dir, Price price, Amount amount);
def add_limit_order(self, dir, price, amount)

Внимание: в Python функции trading_book_update, trading_deals_update, execution_report_update являются свободными, поэтому в них первым параметром передаётся объект strat типа ParticipantStrategy, от которого и нужно вызывать методы стратегии.

Функция add_limit_order выставляет нашу лимитную заявку, где:

  • dir — направление (BID = 0 — покупка, ASK = 1 — продажа).
  • price — цена, по которой заявка будет выставлена.
  • amount — размер заявки.

Будем выставлять нашу заявку внутри функции trading_book_update, когда нам приходит новый стакан order_book. Для определения лучшей цены используем метод best_price класса OrderBook:

C++
Python
void trading_book_update(const OrderBook& order_book) override {
  for (Dir dir : {BID, ASK}) {
    Price best_price = order_book.best_price(dir);
    Amount amount = 1;
    add_limit_order(dir, best_price, amount);
  }
}
def trading_book_update(strat, order_book):
    for dir in (BID, ASK):
        best_price = order_book.best_price(dir)
        amount = 1
        strat.add_limit_order(dir, best_price, amount)

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

C++
Python
const auto& our_orders = order_book.orders();
our_orders = order_book.orders()

Здесь мы используем метод orders, возвращающий ссылку на объект типа SecurityOrdersSnapshot.

Замечание 1: Определённая выше переменная our_orders содержит те заявки, которые мы уже отправили, но на которые ещё не отправили запрос на удаление. Поэтому если для какой-то заявки будет вызван метод delete_order, то к следующему обновлению в our_orders этой заявки точно не будет, даже если в реальности она ещё не успела удалиться.

Замечание 2: Обновление объекта order_book.orders() происходит только между апдейтами, внутри апдейта он не меняется.

Будем ставить заявку, если не существует активной заявки по этому направлению. Для определения наличия активной заявки используем метод active_orders_count(Dir dir) класса SecurityOrdersSnapshot, возвращающий количество наших активных заявок по направлению:

C++
Python
void trading_book_update(const OrderBook& order_book) override {
  const auto& our_orders = order_book.orders();
  for (Dir dir : {BID, ASK}) {
    if (our_orders.active_orders_count(dir) == 0) {
      Price best_price = order_book.best_price(dir);
      Amount amount = 1;
      add_limit_order(dir, best_price, amount);
    }
  }
}
def trading_book_update(strat, order_book):
    our_orders = order_book.orders()
    for dir in (BID, ASK):
        if our_orders.active_orders_count(dir) == 0:
            best_price = order_book.best_price(dir)
            amount = 1
            strat.add_limit_order(dir, best_price, amount)

В такой реализации есть минус — если лучшая цена изменится, то мы на это не отреагируем. Это может привести к тому, что мы долго не будем торговать по одному из направлений. Чтобы получить список наших активных заявок, используем метод orders_by_dir() класса SecurityOrdersSnapshot. Полный код стратегии будет выглядеть так:

C++
Python
#include "participant_strategy.h"

using namespace hftbattle;

namespace {

class UserStrategy : public ParticipantStrategy {
public:
  explicit UserStrategy(const JsonValue& config) { }

  void trading_book_update(const OrderBook& order_book) override {
    const auto& our_orders = order_book.orders();
    for (Dir dir : {BID, ASK}) {
      Price best_price = order_book.best_price(dir);
      Amount amount = 1;
      if (our_orders.active_orders_count(dir) == 0) {
        add_limit_order(dir, best_price, amount);
      } else {  // есть хотя бы одна наша активная заявка
        auto first_order = our_orders.orders_by_dir(dir).front();
        bool on_best_price = (first_order->price() == best_price);
        if (!on_best_price) {  // наша заявка стоит, но не на текущей лучшей цене
          delete_order(first_order);
          add_limit_order(dir, best_price, amount);
        }
      }
    }
  }
};

}  // namespace

REGISTER_CONTEST_STRATEGY(UserStrategy, user_strategy)
# -*- coding: utf-8 -*-

from py_defs import *
from py_defs import Decimal as Price
from common_enums import *


def trading_book_update(strat, order_book):
    our_orders = order_book.orders()
    for dir in (BID, ASK):
        best_price = order_book.best_price(dir)
        amount = 1
        if our_orders.active_orders_count(dir) == 0:
            strat.add_limit_order(dir, best_price, amount)
        else:
            first_order = our_orders.orders_by_dir(dir)[0]
            on_best_price = (first_order.price() == best_price)
            if not on_best_price:  # наша заявка стоит, но не на текущей лучшей цене
                strat.delete_order(first_order)
                strat.add_limit_order(dir, best_price, amount)

Теперь вы можете писать простейшие стратегии.

results matching ""

    No results matching ""