4
Подписаться
1271
Подписчики

Изучите хардкорную стратегию «Стратегия хеджирования контрактов OKEX на C++»

Создано: 2019-08-26 14:30:47, Обновлено: 2024-12-17 20:43:39
comments   2
hits   3252

Изучите хардкорную стратегию «Стратегия хеджирования контрактов OKEX на C++»

Изучите хардкорную стратегию «Стратегия хеджирования контрактов OKEX на C++»

Когда речь идет о стратегиях хеджирования, на разных рынках существует множество стратегий, множество комбинаций и множество идей. Мы начнем с самого классического кросс-периодного хеджирования, чтобы изучить идеи проектирования и концепции стратегий хеджирования. Сегодня рынок цифровых валют гораздо более активен, чем в то время, когда он только сформировался, и появилось множество бирж контрактов, предоставляющих большое количество возможностей для арбитража и хеджирования. Существует бесконечное множество стратегий, таких как спотовый кросс-рыночный арбитраж, спотовый фьючерсный хедж-арбитраж, фьючерсный кросс-периодный арбитраж, фьючерсный кросс-рыночный арбитраж и т. д. Далее рассмотрим «хардкорную» стратегию хеджирования кросс-периодов, написанную на языке C++, где торговым рынком является биржа контрактов OKEX. Стратегия написана на основе «Inventor Quantitative Trading Platform».

  • ### Стратегический принцип

Причина, по которой стратегия несколько хардкорна, заключается в том, что она написана на языке C++, что немного затрудняет ее чтение. Однако это не мешает читателям узнать суть этой стратегии и ее идей. Стратегия относительно лаконична, а длина кода умеренная — всего более 500 строк. Что касается сбора рыночных данных, в отличие от предыдущих стратегий, использующих REST-интерфейс, эта стратегия использует интерфейс WebSocket для получения рыночных данных с бирж. С точки зрения дизайна структура стратегии разумна, связанность кода очень низкая, и ее очень удобно расширять или оптимизировать. Логическое мышление ясное, и этот дизайн не только прост в использовании и расширении. Хорошим примером стратегии обучения является также проектирование стратегии обучения. Принцип стратегии относительно прост: использовать форвардные контракты и краткосрочные контракты для положительного и отрицательного хеджирования, что по сути то же самое, что и кросс-периодное хеджирование товарных фьючерсов. Положительный арбитраж, короткие форвардные контракты и длинные краткосрочные контракты. Хеджирование, длинная позиция по форвардным контрактам и короткая позиция по краткосрочным контрактам. Теперь, когда основные принципы понятны, остается только разобраться, как стратегия запускает хеджирующие позиции, как закрывать позиции и как увеличивать позиции. Методы управления позициями и обработка деталей стратегии. Стратегия хеджирования в основном фокусируется на колебаниях разницы цен базового актива и осуществляет регрессионную торговлю на разнице цен. Однако спред может колебаться незначительно, резко или в одном направлении. Это приводит к неопределенности в хеджировании прибылей и убытков, но риск все равно гораздо меньше, чем при односторонней тенденции. Многие из различных оптимизаций кросс-периодных стратегий выбирают начало с уровня контроля позиции, начиная с триггеров открытия и закрытия. Например, классический индикатор Боллинджера используется в качестве точек открытия и закрытия положительного и отрицательного арбитража при колебаниях разницы цен. Благодаря разумной конструкции и низкой степени связи эту стратегию можно легко модифицировать в стратегию кросс-периодного хеджирования на основе индикатора Боллинджера.

  • ### Анализ стратегического кода

#### Рассматривая код в целом, можно сделать вывод, что он в основном разделен на четыре части.

  • 1. Определение значения перечисления, определение некоторых значений статуса, используемых для обозначения статуса. Некоторые функциональные функции, не связанные со стратегией, такие как функция кодирования URL, функция преобразования времени и т. д., не имеют никакого отношения к стратегии и используются только для обработки данных.
  • 2. Класс генератора данных K-line: Стратегия основана на данных K-line, сгенерированных объектом класса генератора.
  • 3. Класс хеджирования: объекты этого класса могут выполнять определенную логику транзакций, операции хеджирования, механизм обработки деталей стратегии и т. д.
  • 4. Основная функция стратегии, т.е.main функция.main Функция является функцией входа стратегии. Основной цикл выполняется в этой функции. Кроме того, эта функция также выполняет важную операцию, а именно, доступ к интерфейсу веб-сокета биржи для получения переданных тиковых рыночных данных в качестве необработанных материал генератора данных K-line. данные.

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

  • Определение значения перечисления, другие функции

    1. Тип перечисленияState заявление
    enum State {                    // 枚举类型  定义一些 状态
        STATE_NA,                   // 非正常状态
        STATE_IDLE,                 // 空闲
        STATE_HOLD_LONG,            // 持多仓
        STATE_HOLD_SHORT,           // 持空仓
    };
    

    Поскольку некоторые функции в коде возвращают определенное состояние, эти состояния определяются в типе перечисленияStateсередина. Посмотрите, как выглядит кодSTATE_NA То есть это ненормальное состояние.STATE_IDLE Он находится в состоянии простоя, то есть в состоянии, в котором могут проводиться операции хеджирования.STATE_HOLD_LONG Состояние удержания положительной хеджирующей позиции.STATE_HOLD_SHORT Состояние удержания хеджирующей позиции.

    1. Замена строки: Эта функция не вызывается в этой стратегии. Это запасная функция инструмента, которая в основном обрабатывает строки.
    string replace(string s, const string from, const string& to)   
    
    1. Функция преобразования в шестнадцатеричные символыtoHex
    inline unsigned char toHex(unsigned char x)
    
    1. Функция обработки URL-кодирования
    std::string urlencode(const std::string& str)
    
    1. Функция преобразования времени преобразует время из строкового формата в метку времени.
    uint64_t _Time(string &s)
    
  • Класс генератора данных K-line

    class BarFeeder {                                                                       // K线 数据生成器类
        public:
            BarFeeder(int period) : _period(period) {                                       // 构造函数,参数为 period 周期, 初始化列表中初始化
                _rs.Valid = true;                                                           // 构造函数体中初始化 K线数据的 Valid属性。
            }    
    
    
            void feed(double price, Chart *c=nullptr, int chartIdx=0) {                     // 输入数据,nullptr 空指针类型,chartIdx 索引默认参数为 0
                uint64_t epoch = uint64_t(Unix() / _period) * _period * 1000;               // 秒级时间戳祛除不完整时间周期(不完整的_period 秒数),转为 毫秒级时间戳。
                bool newBar = false;                                                        // 标记 新K线Bar 的标记变量
                if (_rs.size() == 0 || _rs[_rs.size()-1].Time < epoch) {                    // 如果 K线数据 长度为 0 。 或者 最后一bar 的时间戳小于 epoch(K线最后一bar 比当前最近的周期时间戳还要靠前)
                    Record r;                                                               // 声明一个 K线bar 结构
                    r.Time = epoch;                                                         // 构造当前周期的K线bar 
                    r.Open = r.High = r.Low = r.Close = price;                              // 初始化 属性
                    _rs.push_back(r);                                                       // K线bar 压入 K线数据结构
                    if (_rs.size() > 2000) {                                                // 如果K线数据结构长度超过 2000 , 就剔除最早的数据。
                        _rs.erase(_rs.begin());
                    }
                    newBar = true;                                                          // 标记
                } else {                                                                    // 其它情况,不是出现新bar 的情况下的处理。
                    Record &r = _rs[_rs.size() - 1];                                        // 引用 数据中最后一bar 的数据。
                    r.High = max(r.High, price);                                            // 对引用数据的最高价更新操作。
                    r.Low = min(r.Low, price);                                              // 对引用数据的最低价更新操作。
                    r.Close = price;                                                        // 对引用数据的收盘价更新操作。
                }
    
    
                auto bar = _rs[_rs.size()-1];                                               // 取最后一柱数据 ,赋值给 bar 变量
                json point = {bar.Time, bar.Open, bar.High, bar.Low, bar.Close};            // 构造一个 json 类型数据
                if (c != nullptr) {                                                         // 图表对象指针不等于 空指针,执行以下。
                   if (newBar) {                                                            // 根据标记判断,如果出现新Bar 
                        c->add(chartIdx, point);                                            // 调用图表对象成员函数add,向图表对象中插入数据(新增K线bar)
                        c->reset(1000);                                                     // 只保留1000 bar的数据
                    } else {
                        c->add(chartIdx, point, -1);                                        // 否则就更新(不是新bar),这个点(更新这个bar)。
                    } 
                }
            }
            Records & get() {                                                               // 成员函数,获取K线数据的方法。
                return _rs;                                                                 // 返回对象的私有变量 _rs 。(即 生成的K线数据)
            }
        private:
            int _period;
            Records _rs;
    };
    

    Этот класс в основном отвечает за обработку полученных тиковых данных в К-линию разницы цен для управления логикой хеджирования стратегии. Некоторые читатели могут задаться вопросом, зачем нам нужны тиковые данные? Зачем нам нужно создавать такой генератор данных K-line? Не лучше ли использовать данные K-line напрямую? Эти три вопроса возникли у меня в голове, когда я писал некоторые стратегии хеджирования. Я нашел ответ, когда написал стратегию хеджирования спреда Боллинджера. Потому что данные K-line отдельного контракта — это статистика изменения цены этого контракта за определенный период. Данные K-line разницы цен между двумя контрактами — это статистика разницы цен в течение определенного периода. Поэтому мы не можем просто взять данные K-line двух контрактов для вычитания и вычислить разницу каждых данных по каждому Бар линии К. Значение, как разница в цене. Самая очевидная ошибка заключается в том, что максимальная и минимальная цены двух контрактов не обязательно совпадают. Поэтому вычитаемое значение не имеет особого смысла. Поэтому нам необходимо использовать тиковые данные в реальном времени, рассчитывать разницу цен в реальном времени и составлять статистику изменений цен за определенный период в реальном времени (т. е. максимум открытия и минимум закрытия в столбце K-line). Таким образом, нам нужен генератор данных K-line как отдельный класс для разделения логики обработки.

  • Хеджирование

    class Hedge {                                                                           // 对冲类,策略主要逻辑。
      public:
        Hedge() {                                                                           // 构造函数
            ...
        };
    
    
        State getState(string &symbolA, Depth &depthA, string &symbolB, Depth &depthB) {        // 获取状态,参数: 合约A名称 、合约A深度数据, 合约B名称、 合约B深度数据
    
    
            ...
        }
        bool Loop(string &symbolA, Depth &depthA, string &symbolB, Depth &depthB, string extra="") {       // 开平仓 策略主要逻辑
    
    
            ...
        }    
    
    
      private:
        vector<double> _addArr;                                     // 对冲加仓列表
        string _state_desc[4] = {"NA", "IDLE", "LONG", "SHORT"};    // 状态值 描述信息
        int _countOpen = 0;                                 // 开仓次数
        int _countCover = 0;                                // 平仓次数
        int _lastCache = 0;                                 // 
        int _hedgeCount = 0;                                // 对冲次数
        int _loopCount = 0;                                 // 循环计数(循环累计次数)
        double _holdPrice = 0;                              // 持仓价格
        BarFeeder _feederA = BarFeeder(DPeriod);            // A合约 行情 K线生成器
        BarFeeder _feederB = BarFeeder(DPeriod);            // B合约 行情 K线生成器
        State _st = STATE_NA;                               // 对冲类型 对象的 对冲持仓状态
        string _cfgStr;                                     // 图表配置 字符串
        double _holdAmount = 0;                             // 持仓量
        bool _isCover = false;                              // 是否平仓 标记
        bool _needCheckOrder = true;                        // 设置是否 检查订单
        Chart _c = Chart("");                               // 图表对象,并初始化
    };
    
    
    

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

    • getState

    Эта функция в основном обрабатывает обнаружение ордеров, отмену ордеров, обнаружение позиций, балансировку позиций и т. д. Потому что в процессе хеджирования транзакций неизбежна односторонняя ситуация (то есть один контракт торгуется, а другой нет). Если она обнаружена в логике ордера, то обрабатывается последующий ордер или закрытие позиции , логика стратегии будет хаотичной. Поэтому при проектировании этой части мы применили другой подход. Если операция хеджирования срабатывает, ордер выставляется один раз. Независимо от того, происходит ли одностороннее хеджирование, хеджирование по умолчанию считается успешным. Затем в функции getState проверяется баланс позиции, а логика проверки и обработки остаток отделен.

    • Loop

    Торговая логика стратегии заключена в этой функции, где вызовgetState , используйте объект генератора данных K-линии для генерации данных K-линии разницы цен и принимайте решения относительно логики хеджирования открытия, закрытия и добавления позиций. Также имеются некоторые операции по обновлению данных для диаграмм.

  • Основная функция стратегии

    void main() {  
    
    
        ...
    
    
        string realSymbolA = exchange.SetContractType(symbolA)["instrument"];    // 获取设置的A合约(this_week / next_week / quarter ) ,在 OKEX 合约 当周、次周、季度 对应的真实合约ID 。
        string realSymbolB = exchange.SetContractType(symbolB)["instrument"];    // ...
    
    
        string qs = urlencode(json({{"op", "subscribe"}, {"args", {"futures/depth5:" + realSymbolA, "futures/depth5:" + realSymbolB}}}).dump());    // 对 ws 接口的要传的参数进行 json 编码、 url 编码
        Log("try connect to websocket");                                                                                                            // 打印连接 WS接口的信息。
        auto ws = Dial("wss://real.okex.com:10442/ws/v3|compress=gzip_raw&mode=recv&reconnect=true&payload="+qs);     // 调用FMZ API Dial 函数 访问  OKEX 期货的 WS 接口
        Log("connect to websocket success");
    
    
        Depth depthA, depthB;                               // 声明两个 深度数据结构的变量 用于储存A合约和B合约 的深度数据
        auto fillDepth = [](json &data, Depth &d) {         // 用接口返回的json 数据,构造 Depth 数据的代码。
            d.Valid = true;
            d.Asks.clear();
            d.Asks.push_back({atof(string(data["asks"][0][0]).c_str()), atof(string(data["asks"][0][1]).c_str())});
            d.Bids.clear();
            d.Bids.push_back({atof(string(data["bids"][0][0]).c_str()), atof(string(data["bids"][0][1]).c_str())});
        };
        string timeA;   // 时间 字符串 A 
        string timeB;   // 时间 字符串 B 
        while (true) {
            auto buf = ws.read();                           // 读取 WS接口 推送来的数据
    
    
            ...
    
    
    }
    

    После запуска стратегии она начинает выполняться из основной функции. Во время инициализации основной функции стратегия подписывается на тиковый рынок интерфейса вебсокета. Основная задача основной функции — построить основной цикл, непрерывно получать информацию о тиках, передаваемую веб-сокет-интерфейсом биржи, а затем вызывать функцию-член объекта класса хеджирования: функцию Loop. Торговая логика в функции Loop основана на рыночных данных. Необходимо пояснить, что упомянутый выше тиковый рынок на самом деле представляет собой интерфейс данных глубины книги заявок, который получает данные книги заявок каждого уровня. Однако стратегия использует только данные с первого уровня, которые фактически аналогичны данным тикового рынка. Стратегия не использует данные с других уровней, а также не использует значения объема ордера с первого уровня. Давайте подробнее рассмотрим, как стратегия подписывается на данные интерфейса веб-сокета и как она настраивается.

    string qs = urlencode(json({{"op", "subscribe"}, {"args", {"futures/depth5:" + realSymbolA, "futures/depth5:" + realSymbolB}}}).dump());    
    Log("try connect to websocket");                                                                                                            
    auto ws = Dial("wss://real.okex.com:10442/ws/v3|compress=gzip_raw&mode=recv&reconnect=true&payload="+qs);     
    Log("connect to websocket success");
    

    Во-первых, вам необходимо закодировать URL-адрес параметра json сообщения подписки, передаваемого интерфейсом подписки, то есть:payload Значение параметра. Затем более важным шагом является вызов функции интерфейса API количественной торговой платформы Inventor.Dial функция.Dial Функцию можно использовать для доступа к интерфейсу Exchange WebSocket. Здесь мы делаем некоторые настройки, чтобы включить создание объекта управления соединением websocket ws для автоматического повторного подключения после отключения (сообщение о подписке по-прежнему использует строку значения qs параметра payload). Для реализации этой функции вам необходимоDial Добавьте параметры конфигурации в строку параметров функции.

    DialПараметры функции начинаются следующим образом:

    wss://real.okex.com:10442/ws/v3
    

    Это адрес интерфейса веб-сокета, к которому необходимо получить доступ и который затем можно использовать.| Разделение. compress=gzip_raw&mode=recv&reconnect=true&payload="+qs Все это параметры конфигурации.

    Название параметра Описание
    compress compress — это метод сжатия. Интерфейс веб-сокета OKEX использует gzip_raw, поэтому он установлен на gzip_raw
    mode mode — это режим, а его параметры: dual, send и recv. двойной означает двунаправленный, отправляющий сжатые данные и получающий сжатые данные. send — отправка сжатых данных. recv получает сжатые данные и распаковывает их локально.
    reconnect reconnect — установить ли переподключение. reconnect=true включает переподключение. Если не установлено, переподключение отключено по умолчанию.
    полезная нагрузка Полезная нагрузка — это сообщение о подписке, которое необходимо отправить при повторном подключении ws.

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

  • Контроль положения

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

  for (int i = 0; i < AddMax + 1; i++) {                                          // 构造 控制加仓数量的数据结构,类似 波菲纳契数列 对冲数量 比例。
      if (_addArr.size() < 2) {                                                   // 前两次加仓量变化为: 加一倍对冲数量 递增
          _addArr.push_back((i+1)*OpenAmount);
      }
      _addArr.push_back(_addArr[_addArr.size()-1] + _addArr[_addArr.size()-2]);   // 最后 两个加仓数量相加,算出当前的加仓数量储存到 _addArr数据结构中。
  }

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

  • ### Закрытие позиции: стоп-лосс, тейк-профит

Фиксированный спред тейк-профита, спред стоп-лосса. Когда разница в цене позиции достигает позиции тейк-профит или стоп-лосс, будет исполнен тейк-профит или стоп-лосс.

  • ### Вход и выход из рыночного цикла

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

  • ### Стратегическая диаграмма

Стратегия автоматически генерирует график разницы цен в виде свечей и отмечает соответствующую информацию о транзакциях.

Операция рисования пользовательской диаграммы стратегии C++ также очень проста. Вы можете видеть, что в конструкторе класса хеджа мы используем записанную строку конфигурации диаграммы _cfgStr для настройки объекта диаграммы _c._c — класс хеджа. Когда инициализируется закрытый член, вызывается функция интерфейса API количественной пользовательской диаграммы изобретателя.Chart Объект диаграммы, построенный функцией.

  _cfgStr = R"EOF(
  [{
  "extension": { "layout": "single", "col": 6, "height": "500px"},
  "rangeSelector": {"enabled": false},
  "tooltip": {"xDateFormat": "%Y-%m-%d %H:%M:%S, %A"},
  "plotOptions": {"candlestick": {"color": "#d75442", "upColor": "#6ba583"}},
  "chart":{"type":"line"},
  "title":{"text":"Spread Long"},
  "xAxis":{"title":{"text":"Date"}},
  "series":[
      {"type":"candlestick", "name":"Long Spread","data":[], "id":"dataseriesA"},
      {"type":"flags","data":[], "onSeries": "dataseriesA"}
      ]
  },
  {
  "extension": { "layout": "single", "col": 6, "height": "500px"},
  "rangeSelector": {"enabled": false},
  "tooltip": {"xDateFormat": "%Y-%m-%d %H:%M:%S, %A"},
  "plotOptions": {"candlestick": {"color": "#d75442", "upColor": "#6ba583"}},
  "chart":{"type":"line"},
  "title":{"text":"Spread Short"},
  "xAxis":{"title":{"text":"Date"}},
  "series":[
      {"type":"candlestick", "name":"Long Spread","data":[], "id":"dataseriesA"},
      {"type":"flags","data":[], "onSeries": "dataseriesA"}
      ]
  }
  ]
  )EOF";
  _c.update(_cfgStr);                 // 用图表配置 更新图表对象
  _c.reset();                         // 重置图表数据。
  • Вызов_c.update(_cfgStr); использовать _cfgStr Конфигурация объекта диаграммы.
  • Вызов_c.reset(); Сбросить данные диаграммы.

Когда коду стратегии необходимо вставить данные в диаграмму, он также вызывается напрямую_функция-член объекта c, или_Ссылка c передается в качестве параметра, а затем вызывается функция-член объекта (метод) _c для выполнения операций обновления и вставки данных диаграммы. Например:

  _c.add(chartIdx, {{"x", UnixNano()/1000000}, {"title", action},  {"text", format("diff: %f", opPrice)}, {"color", color}});

После размещения ордера отметьте его на графике японских свечей.

Как показано ниже, рисование K-линии выполняется путем вызова функции-члена класса BarFeeder.feed Когда объект диаграммы_Ссылка на c передается как параметр.

  void feed(double price, Chart *c=nullptr, int chartIdx=0)

Прямо сейчасfeedПараметр функции c.

  json point = {bar.Time, bar.Open, bar.High, bar.Low, bar.Close};            // 构造一个 json 类型数据
  if (c != nullptr) {                                                         // 图表对象指针不等于 空指针,执行以下。
     if (newBar) {                                                            // 根据标记判断,如果出现新Bar 
          c->add(chartIdx, point);                                            // 调用图表对象成员函数add,向图表对象中插入数据(新增K线bar)
          c->reset(1000);                                                     // 只保留1000 bar个数据
      } else {
          c->add(chartIdx, point, -1);                                        // 否则就更新(不是新bar),这个点(更新这个bar)。
      } 
  }

Вызывая объект диаграммы_сaddФункция-член вставляет новые данные K-line Bar в диаграмму. Код:c->add(chartIdx, point);

  • ### Бэктестинг

Изучите хардкорную стратегию «Стратегия хеджирования контрактов OKEX на C++»

Изучите хардкорную стратегию «Стратегия хеджирования контрактов OKEX на C++»

Изучите хардкорную стратегию «Стратегия хеджирования контрактов OKEX на C++»

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

Адрес стратегии: https://www.fmz.com/strategy/163447

Для получения более интересных стратегий посетите «Платформу количественной торговли Inventor»: https://www.fmz.com