리소스 로딩... 로딩...

"C++ 버전의 OKEX 계약 헤지 전략"에서 하드 코어 전략을 배우게 됩니다.

저자:발명가들의 수량화 - 작은 꿈, 2019-08-26 14:30:47, 업데이트: 2023-10-19 21:09:01

img

"C++ 버전의 OKEX 계약 헤지 전략"에서 하드 코어 전략을 배우게 됩니다.

헤지핑 전략에 관해서는 다양한 전략, 다양한 조합, 다양한 아이디어가 다양한 시장에 있습니다. 우리는 가장 고전적인 연장 헤지핑에서 헤지핑 전략의 디자인 아이디어와 개념을 처음 탐구했습니다. 오늘날, 디지털 통화 시장의 활력은 시장이 형성되기 전에 훨씬 더 높고 많은 계약 거래소가 등장하여 많은 유리한 헤지핑 기회를 제공합니다. 현장 트랜스 시장 이차, 현장 이차, 미래 이차, 미래 이차, 미래 이차, 이차 시장 이차 등 전략의 계층은 끝없이 많습니다. 우리는 함께 C++ 언어로 작성된 개념에 대해 이야기했습니다. 거래 시장은 OKEX 계약 거래소의 "하드 코어" 연장 헤지핑 전략을 개발자 "개발 거래 플랫폼"에 기반하여 작성했습니다.

  • 전략적 원칙

    왜 전략이 다소 고질적이라고 말할 수 있는 이유는 전략이 C++ 언어를 사용하여 작성되었으며, 전략의 읽기 어려움이 약간 높기 때문입니다. 그러나 독자가 이 전략의 디자인과 생각의 본질을 배우는 것을 방해하지 않습니다. 전략 전체 내용은 간결하고 코드 길이는 500줄 이상으로 적당합니다. 시장 데이터 획득 측면에서는 이전 전략의 rest 인터페이스를 사용하는 것과 달리 웹 소켓 인터페이스를 사용하여 거래소에서 트래픽을 전달합니다. 디자인 측면에서는 전략 구조가 합리적이고, 코드 이 낮은 편의성, 확장 또는 최적화 용이성; 논리적인 사고가 명확하며, 이러한 디자인은 단순히 사용, 확장 용이성뿐만 아니라; 교육 전략으로서, 학습 전략 설계도 좋은 예이다. 전략 원리는 비교적 간단하며, 즉 장기 계약과 근기 계약의 수정, 반투자 헤딩, 기본적으로 상품 선물의 장기 헤딩과 일치한다. 토, 장기 계약을 하지, 단기 계약을 하지. 기본 원리를 명확히 하고, 남은 것은 전략이 헤지 오픈을 어떻게 촉발하는지, 어떻게 평준화하는지, 어떻게 상승하는지, 어떻게 포지션을 제어하는지, 전략 세부 사항을 처리하는 방법이다. 헤지핑 전략은 주로 지표의 물가 차이의 변동에 초점을 맞추고, 차이에 대한 회귀 거래를 한다. 그러나, 차이에는 작은 변동, 또는 큰 변동, 또는 일방적인 변동이 있을 수 있다. 이것은 헤지핑 이익/손실의 불확실성을 가져오지만 위험은 일방적인 추세보다 훨씬 작다. 연장 전략의 다양한 최적화는 많은 경우 포지션 제어 수준에서 출발하고, 오픈 플라이스 포지션을 유발하는 것을 선택한다. 예를 들어, 클래식한 브린 지표를 사용해서 가격 변동에 대비하여, 앞면, 뒷면, 평행 지점을 사용한다. 이 전략은 합리적인 설계로, 결률이 낮기 때문에, 브린 지표의 연장 헤지핑 전략으로도 쉽게 수정될 수 있다.

  • 전략 코드 분석

    이 문헌은 코드를 살펴보면, 코드가 크게 네 부분으로 나뉘어 있다고 결론 지을 수 있습니다.

    • 1. 명함값 정의, 상태값을 정의하여 상태를 표시한다. url 코딩 함수, 시간 변환 함수와 같은 전략 생각과 관련이 없는 함수 함수들은 데이터 처리 용도로만 사용됩니다.
    • 2.K线数据生成器类:策略由该生成器类对象生成的K线数据驱动。
    • 3.对冲类:该类的对象可以执行具体的交易逻辑,对冲操作、策略细节的处理机制等。
    • 4.策略主函数,也就是 main이 함수들은main함수는 정책의 입력 함수이며, 주요 루프는 이 함수 안에서 실행되며, 또한 이 함수 안에서 중요한 동작을 수행하는데, 즉, 거래소의 웹소켓 인터페이스를 접근하여, K 라인 데이터 생성기의 원료 데이터로서 푸싱된 틱 시장 데이터를 얻는다.

    전략 코드 전체에 대한 이해로, 우리는 단계적으로 각 요소를 분석하여 전략의 설계, 아이디어, 기술을 완전히 배울 수 있습니다.

    • 명제 값 정의, 다른 함수 함수

      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반투자 헤지 포지션을 보유한 상태.

      2, 문자열 대체, 이 정책에서 호출되지 않는, 백업 도구 함수로, 문자열을 주로 처리한다.

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

      3, 16자리 함수로 변환되는 함수toHex

      inline unsigned char toHex(unsigned char x)
      

      4, url 코딩을 처리하는 함수

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

      5, 시간 변환 함수, 문자열 형식의 시간을 시간 으로 변환합니다.

      uint64_t _Time(string &s)
      
    • K 라인 데이터 생성자 클래스

      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 라인으로 처리하여 전략적 헤지핑 논리를 구동하는 역할을 합니다. 어떤 독자들이 의문을 가질 수 있는 것은, 왜 틱 데이터를 사용해야 하는가? 왜 이런 K 라인 데이터 생성기를 구성해야 하는가? 직접적으로 K 라인 데이터를 사용하는 것이 좋지 않은가? 이러한 의문은 3번이나 반복되어 왔으며, 제가 초기 헤지킹 전략을 쓰면서도 튀어나왔다. 그리고 두 계약의 차이값의 K선 데이터들은 특정 주기 내의 차이값 변화의 통계에 해당한다. 따라서 단순히 두 계약의 각각의 K선 데이터들을 셈 연산으로 하여 각 K선 Bar에 있는 각 데이터들의 차이값을 계산할 수 없다. 따라서 우리는 실시간 틱 데이터를 사용해야 하며, 실시간으로 유가 차이를 계산하고, 실시간으로 일정 주기에 따른 가격 변화를 통계 (즉, K선 기둥의 높은 열과 낮은 수요) 해야 합니다. 그래서 우리는 K선 데이터 생성기를 필요로 합니다.

    • 헤드리지 클래스

      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를 언급하지 않고, 주로 객체 초기화이다. 나머지, 주로 2개의 함수가 있다.

      • getState

        이 함수는 주로 주문 검증, 주문 취소, 포지션 검증, 포지션 균형 등의 작업을 처리한다. 헤지핑 거래 과정에서 단발의 상황을 피할 수 없기 때문에 (즉, 계약이 성립, 계약이 성립하지 않음) 만약 하위 주문 논리에서 검사를 수행하고, 다음 주문을 처리하거나 평정하면 전략 논리가 비교적 혼란스러울 것이다. 그래서 이 부분을 설계할 때 다른 생각을 취했다. 만약 헤지핑 동작을 촉발하면 다음 번, 단발의 경우와 상관없이, 기본 헤지핑이 성공한 다음, getState 함수에서 포지션 균형을 검출하고, 독립적으로 처리 평형을 검출하는 이 논리를 발굴한다.

      • 루프

        이 함수에는 전략의 트랜잭션 로직이 포괄되어 있습니다.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接口 推送来的数据
              
              ...
              
      }
      

      정책의 시작은 메인 함수에서 실행되기 시작하여 메인 함수의 초기화 작업에서 웹소켓 인터페이스의 틱 행렬을 구독합니다. 메인 함수의 주요 작업은 메인 루크를 구성하고 지속적인 수신 거래소 웹소켓 인터페이스에서 전달된 틱 행렬을 생성하고 헤지 타입 객체의 멤버 함수를 호출합니다. 한 가지 설명해야 할 점은, 위의 언급된 틱 시장은 실제로 구독의 주문 얇은 깊이 데이터 인터페이스이며, 각 파일의 주문 얇은 데이터를 얻습니다. 그러나 전략은 첫 번째 파일의 데이터를 사용하지만 실제로 틱 시장 데이터와 거의 같습니다. 전략은 다른 파일의 데이터를 사용하지 않으며 첫 번째 파일의 주문량 값을 사용하지 않습니다. 자세한 내용은 웹소켓 인터페이스의 데이터를 구독하는 방법과 설정하는 방법에 대한 정책을 참조하십시오.

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

      먼저, json 파라미터에 의해 전달되는 구독 메시지에 대한 url를 코딩합니다.payload파라미터의 값. 그리고 더 중요한 단계는 발명자의 양적 거래 플랫폼의 API 인터페이스 함수를 호출하는 것입니다.Dial이 함수들은Dial이 함수는 거래소 웹소켓 인터페이스에 액세스 할 수 있습니다. 우리는 여기서 생성될 웹소켓 연결 제어 객체 ws가 자동으로 끊어질 수 있도록 설정합니다.Dial함수의 변수 문자열에 설정 옵션을 추가합니다.

      Dial함수 파라그램의 시작 부분은 다음과 같습니다.

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

      웹소켓 인터페이스 주소를 사용해야 합니다|이 글은 이 부분에서 읽었습니다.compress=gzip_raw&mode=recv&reconnect=true&payload="+qs모든 것은 설정 파라미터입니다.

      변수 이름 설명
      압축 compress는 압축 모드로, OKEX 웹소켓 인터페이스는 gzip_raw를 사용합니다. 이 모드는 gzip_raw로 설정됩니다.
      모드 모드는 모드로, 선택 가능한 dual, send, recv 세 가지;;dual는 쌍방향으로, 압축 데이터를 전송하고 압축 데이터를 수신한다;;send는 압축 데이터를 전송한다;;recv는 압축 데이터를 수신하고, 로컬로 압축을 해소한다。
      다시 연결 reconnect는 재연결을 설정하는지 여부를 표시하고, reconnect=true는 재연결을 활성화하고, 기본적으로 재연결을 설정하지 않습니다.
      유해물 payload는 ws로 재결합될 때 전송해야 하는 가입 메시지이다.

      이렇게 설정되면, 웹소켓 연결이 끊어지면, 발명자 양적 거래 플랫폼, 호스트 하위 시스템도 자동으로 재연결하여 최신 시장 데이터를 신속히 얻을 수 있습니다. 이 지표는 이 지표의 모든 변동을 파악하고 적절한 헤지 시장에 빠르게 도달하는 지표입니다.

  • 위치 제어

    포지션 컨트롤은 "포피나치"와 비슷한 수열의 헤지 포지션 비율을 사용하여 제어합니다.

    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 제어 주기는 전략의 오픈 포지션 평소에 특정 동적 통제를 수행한다.

  • 전략 그래프

    전략은 자동으로 K 라인 차트를 생성하고 관련 거래 정보를 표시합니다.

    C++ 정책 사용자 지정 그래프 도화 작업 또한 매우 간단합니다. 헤지프 클래스의 구성 함수에서 볼 수 있듯이, 우리는 잘 쓰인 그래프 구성 문자열_cfgStr를 사용하여 그래프 객체_c에 설정했습니다.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 라인 차트에 레이블 기록을 입력합니다.

    아래에서, 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)。
        } 
    }
    

    그래프 객체 _c를 호출하여add멤버 함수, 차트에 새로운 K 라인 Bar 데이터를 삽입합니다. 코드:c->add(chartIdx, point);

  • 재검토

    img

    img

    img

이 정책은 학습 교류용으로만 사용되며, 실제 디스크 사용 시 실제 디스크 상황에 따라 수정하여 최적화하십시오.

그라운드:https://www.fmz.com/strategy/163447

더 많은 흥미로운 전략은 "발명자 양적 거래 플랫폼"에서 볼 수 있습니다:https://www.fmz.com


관련

더 많은