Die Ressourcen sind geladen. Beförderung...

"OKEX-Kontrakt-Hedging-Strategien in C++"

Schriftsteller:Die Erfinder quantifizieren - Kleine Träume, Erstellt: 2019-08-26 14:30:47, Aktualisiert: 2024-12-17 20:43:39

img

"OKEX-Kontrakt-Hedging-Strategien in C++"

Was die Hedging-Strategien angeht, gibt es viele verschiedene Strategien, verschiedene Kombinationen und verschiedene Ideen in den verschiedenen Märkten. Wir haben die Designideen und Ideen für die Hedging-Strategien von den klassischsten Überlauf-Hedging begannen. Heute ist der Markt für digitale Währungen viel aktiver als zu Beginn der Entstehung des Marktes, und es gibt viele Kontraktbörsen, die eine Vielzahl von Möglichkeiten für die Hedging-Leistung bieten.

  • Die Strategie

    Der Grund, warum man die Strategie als etwas Hardcore bezeichnet, liegt darin, dass sie in C++ geschrieben wurde und etwas schwieriger zu lesen ist. Aber das hindert den Leser nicht daran, die Essenz der Strategie zu erlernen. Die Strategie ist übersichtlich, die Code ist mittelmäßig lang und nur über 500 Zeilen. In Bezug auf das Design ist die Strategiestruktur vernünftig, die Code-Kontexten sind niedrig, leicht zu erweitern oder zu optimieren. Der logische Gedanke ist klar, ein solches Design ist nicht nur benutzerfreundlich und leicht zu erweitern. Als Lehrstrategie ist die Lernstrategie auch ein gutes Beispiel. Ich bin ein großer Künstler und ich habe ein großes Interesse daran, dass ich in der Lage bin, meine Arbeit zu leisten. Der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission, der Präsident der Kommission und der Präsident der Kommission. Wenn die Grundlagen klar sind, bleibt die Strategie, wie man Hedge-Positionen anfängt, wie man einbricht, wie man die Positionen erhöht. Die Hedging-Strategie konzentriert sich hauptsächlich auf die Schwankungen der Kursdifferenz, um auf die Differenz zurückzugreifen. Es ist jedoch möglich, dass die Differenz geringfügig, stark oder einseitig schwankt. Dies führt zu Unsicherheiten bei den Hedging-Gewinnen und Verlusten, aber auch zu weit geringeren Risiken als bei einem einseitigen Trend. Für die Optimierung der Langzeitstrategien wird viel von der Positionskontrollebene und der Auslösung der Eröffnungs-Plaze gewählt. Zum Beispiel kann die klassische Bringin-Anzeige als Differenz- und Differenz-Punkt verwendet werden. Diese Strategie kann leicht in eine Bringin-Langzeit-Hedging-Strategie umgewandelt werden, da sie vernünftiger gestaltet ist und die Konzentration sehr niedrig ist.

  • Strategische Codeanalyse

    Der Code ist in etwa in vier Teile gegliedert.

    • Einige Funktionsfunktionen, die nichts mit der Strategie zu tun haben, wie z.B. die URL-Codierung, die Zeitumwandlung usw. Diese Funktionen haben nichts mit der Strategie zu tun und werden lediglich für die Datenverarbeitung verwendet.
    • 2.K线数据生成器类:策略由该生成器类对象生成的K线数据驱动。
    • 3.对冲类:该类的对象可以执行具体的交易逻辑,对冲操作、策略细节的处理机制等。
    • 4.策略主函数,也就是 mainDie Funktion.mainDie Funktion ist die Inputfunktion der Strategie, in der die wichtigsten Schleifen ausgeführt werden. Darüber hinaus führt sie eine wichtige Operation durch, die den Websocket-Interface der Börse aufruft, um die geschobenen Ticket-Marktdaten zu erhalten, die als Rohdaten für den K-Leinendatengenerator dienen.

    Mit einem ganzheitlichen Verständnis des Strategiecodes können wir die Konzepte, Ideen und Techniken der Strategie schrittweise analysieren, um sie vollständig zu erlernen.

    • Definition von Aufzählwerten, andere Funktionsfunktionen

      1. Liste der TypenStateErklärung

      enum State {                    // 枚举类型  定义一些 状态
          STATE_NA,                   // 非正常状态
          STATE_IDLE,                 // 空闲
          STATE_HOLD_LONG,            // 持多仓
          STATE_HOLD_SHORT,           // 持空仓
      };
      

      Da einige Funktionen im Code einen Zustand zurückgeben, sind diese Zustände definiert in einem Aufzähltyp.StateDas ist ein großes Problem. Sie sehen, dass es im Code erscheint.STATE_NADas ist ein abnormaler Zustand.STATE_IDLEDer Standort wird als Leerstand bezeichnet, d.h. als Standort, in dem sich die Absicherung durchführen lässt.STATE_HOLD_LONGDer Status für das Halten einer korrekten Hedging-Position.STATE_HOLD_SHORTDer Status für die Halte von Gegen-Hedge-Positionen.

      2, String Replacement, keine Anrufung in dieser Richtlinie, als eine Bespare-Toolfunktion, die String-Hauptarbeit verarbeitet.

      string replace(string s, const string from, const string& to)   
      

      Funktion 3 ist eine Funktion, die in sechzehnstellige Zeichen umgewandelt wirdtoHex

      inline unsigned char toHex(unsigned char x)
      

      4. Funktionen, die URL-Codes verarbeiten

      std::string urlencode(const std::string& str)
      

      5. Die Zeitumwandlungsfunktion, die die Zeit in Stringformat in eine Zeitstange umwandelt.

      uint64_t _Time(string &s)
      
    • K-Linien-Daten-Generatoren

      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;
      };
      

      Diese Kategorie ist hauptsächlich dafür verantwortlich, die gewonnenen Tickdaten in Differenz-K-Linien zu verarbeiten, um die strategische Hedging-Logik zu steuern. Einige Leser haben möglicherweise Fragen, warum man Tick-Daten verwenden sollte? Warum sollte man einen solchen K-Linien-Daten-Generator konstruieren? Ist es schlecht, direkt mit K-Linien-Daten zu arbeiten? Die Differenz zwischen den Preisen der beiden Verträge ist eine Statistik der Preisänderungen der Differenz in einem bestimmten Zeitraum. Daher kann man nicht einfach die Differenz der einzelnen Daten auf jeder K-Linie berechnen. Wir benötigen also Tick-Daten in Echtzeit, um die Differenz in Echtzeit zu berechnen, um die Preisänderungen innerhalb eines bestimmten Zyklus in Echtzeit zu berechnen (d.h. die hohen und niedrigen Einnahmen in den K-Säulen).

    • Absicherungsklasse

      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("");                               // 图表对象,并初始化
      };
      
      
      

      Da der Code relativ lang ist, wurde ein Teil weggelassen, der hauptsächlich die Struktur dieser Hedge-Klasse zeigt, und die Konstruktionsfunktion Hedge wird nicht erwähnt, die hauptsächlich für die Objektinitialisierung verwendet wird.

      • GetState

        Diese Funktion befasst sich hauptsächlich mit Auftragsermittlung, Auftragsermächtigung, Positionsermittlung, Positionsgleichgewicht usw. Da bei einem Hedging-Trading eine Situation, in der man nicht vermeiden kann, dass ein einseitiges Handeln (d. h. ein Vertrag geschlossen, ein Vertrag nicht geschlossen) nicht vermieden werden kann, wird die Strategielogik verwirrender, wenn eine Untersuchung in der Nachbestellungslogik durchgeführt wird und dann eine Nachfrage oder ein Ausgleich verarbeitet wird.

      • Schleife

        Die Transaktionslogik der Strategie wird in dieser Funktion umhüllt, in der die AnrufegetStateDie K-Linien-Daten-Generator-Objekte werden verwendet, um Differenz-K-Linien-Daten zu erzeugen, um Hedge-Off-, Brechung- und Aufstockungslogik zu beurteilen. Es gibt auch einige Datenaktualisierungen für die Diagramme.

    • Strategie-Hauptfunktion

      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接口 推送来的数据
              
              ...
              
      }
      

      Die wichtigste Aufgabe der Main-Funktion besteht darin, einen Hauptschleife zu erstellen, die ununterbrochen von der Websocket-Interface empfangende Ticks aus dem Exchange-Websocket-Interface anruft und dann die Mitgliedfunktionen des Hedge-Objekts: Loop-Funktionen anruft. Die Transaktionslogik in der Loop-Funktion wird von den Verhaltensdaten gesteuert. Ein Punkt, den ich noch einmal erwähnen möchte, ist, dass der Tick-Markt in Wirklichkeit eine tiefe Datenoberfläche für die Abonnement-Bestellungen ist, in der die Daten für jede Gruppe abgerufen werden. Die Strategie verwendet jedoch nur die Daten der ersten Gruppe, die in der Tat ähnlich sind wie die Daten für den Tick-Markt. Die Strategie verwendet weder die Daten der anderen Gruppen noch die Ordermengen der ersten Gruppe. Siehe hier, wie Sie die Websocket-Interface-Daten abonnieren und wie Sie sie einrichten.

      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");
      

      Zuerst müssen wir die URLs der Abonnementnachrichten, die von der Abonnements-Schnittstelle übertragen werden, mit den json-Parametern kodieren.payloadDer Wert der Parameter. Dann ist ein wichtigerer Schritt, die API-Interface-Funktion der Erfinder-Quantifizierungsplattform aufzurufen.DialDie Funktion.DialDie Funktion kann auf die Websocket-Schnittstelle der Börse zugegriffen werden. Hier werden einige Einstellungen vorgenommen, so dass die zu erstellende Websocket-Verbindung des Steuerobjekts ws automatisch unterbrochen wird.DialZusätzliche Konfigurationsoptionen in die Parameterzeilen der Funktion.

      DialDer Anfang der Funktionsparameter lautet:

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

      Die Websocket-Interface-Adresse, auf die zugegriffen werden muss, wird dann verwendet.|Ich habe mich gefreut.compress=gzip_raw&mode=recv&reconnect=true&payload="+qsSie sind alle Konfigurationsparameter.

      Name der Parameter Beschreibung
      Kompressen compress ist der Kompressionsmodus, der von der OKEX-Websocket-Oberfläche gzip_raw verwendet wird.
      Modus Mode ist ein Modus, wählbar dual, send, recv. Drei Arten; dual ist zweiseitig, sendet Kompressionsdaten, empfängt Kompressionsdaten; send send send Kompressionsdaten; recv empfängt Kompressionsdaten, lokal dekomprimiert.
      Wiederanschluss reconnect zeigt an, ob die Wiederverbindung eingestellt ist, reconnect=true zeigt an, ob die Wiederverbindung aktiviert ist, ohne dass die Default-Nicht-Wiederverbindung eingestellt ist.
      Nutzlast Die Abonnementnachricht, die beim Wiederaufbau von payloads als ws gesendet werden muss.

      Wenn die Websocket-Verbindung unterbrochen wird, wird die Quantifizierung der Inventor-Trading-Plattform automatisch durch das Host-Basis-System wieder verbunden, um rechtzeitig auf aktuelle Marktdaten zuzugreifen. Sie können sich an jedem Kursschwanken halten und schnell die richtigen Hedging-Marktbedingungen finden.

  • Positionssteuerung

    Positionskontrolle wird mit dem Verhältnis der Hedgingpositionen, ähnlich dem von "Boffinach", durchgeführt.

    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数据结构中。
    }
    

    Man kann sehen, dass die Anzahl der erhöhte Lagerpositionen die Summe der letzten beiden Positionen ist. Solche Positionskontrolle ermöglicht es, je größer die Differenz ist, um die Anzahl der Gewinnabwehr zu erhöhen, und die Positionen zu verteilen, um so kleine Positionen mit geringen Differenzschwankungen zu erfassen.

  • Gleichgewicht: Stop-Loss-Stop

    Der Preis für den Verkauf von Produkten, die in den USA verkauft werden, wird von den Herstellern in den USA und in den USA festgesetzt. Die Differenz zwischen den Anteilen wird bis zur Erreichung der Pump-Position und der Stop-Loss-Position gestoppt.

  • Markteinführung, Markteinführung, Zyklusdesign

    Parameter NPeriod Die Periode, die von NPeriod gesteuert wird, hat eine gewisse dynamische Kontrolle über die Strategie der Eröffnungsposition.

  • Strategie-Diagramm

    Die Strategie erzeugt automatisch einen K-Linien-Graph der Differenz und markiert die entsprechenden Transaktionsinformationen.

    C++-Strategien zur Anpassung von Diagrammen sind auch sehr einfach, wie man in der Konstruktionsfunktion für die Hedge-Klasse sehen kann. Wir verwenden die gut geschriebene Graphkonfigurationsstring_cfgStr Konfiguration für das Graphobjekt_c, _c ist das private Mitglied der Hedge-Klasse.ChartGrafikobjekte, die von Funktionen konstruiert werden.

    _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();                         // 重置图表数据。
    
    • Anrufe_c.update(_cfgStr);Verwenden Sie _cfgStr, um ein Diagrammobjekt zu konfigurieren.
    • Anrufe_c.reset();Die Grafikdaten werden wiederhergestellt.

    Wenn die Strategiecode Daten in ein Diagramm einfügen möchte, kann dies auch durch den direkten Aufruf der Mitgliederfunktion des _c-Objekts oder die Übermittlung der Referenz zu _c als Parameter durchgeführt werden, um die Daten des _c-Objekts zu aktualisieren. Zum Beispiel:

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

    Nach der Bestellung wird ein Etikett auf dem K-Line-Chart angezeigt.

    Hier wird die Zeichnung der K-String als Mitglied der BarFeeder-Klasse aufgerufen.feedWenn Sie eine Referenz zu einem Chartobjekt _c als Parameter übertragen haben, wird eine Referenz zu einem Chartobjekt _c als Parameter übertragen.

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

    Das heißtfeedDie Form der Funktion ist 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)。
        } 
    }
    

    Sie können das _c-Objekt aufrufen.addDie Mitgliederfunktion, die neue K-Linien-Bar-Daten in das Diagramm einfügt. Der Code:c->add(chartIdx, point);

  • Wiederholung

    img

    img

    img

Diese Strategie dient nur zum Lernen von Kommunikation.

Die Strategie ist unter:https://www.fmz.com/strategy/163447

Weitere interessante Tipps finden Sie unter "Inventor Quantitative Trading Platforms":https://www.fmz.com


Verwandt

Mehr