Tài nguyên đang được tải lên... tải...

"OKEX C++ Contract Hedging Strategy" giúp bạn học chiến lược lõi cứng.

Tác giả:Những nhà phát minh định lượng - những giấc mơ nhỏ, Tạo: 2019-08-26 14:30:47, Cập nhật: 2023-10-19 21:09:01

img

"OKEX C++ Contract Hedging Strategy" giúp bạn học chiến lược lõi cứng.

Nói về chiến lược đầu cơ, các thị trường có nhiều chiến lược khác nhau, nhiều sự kết hợp khác nhau, nhiều ý tưởng khác nhau. Chúng tôi bắt đầu nghiên cứu các ý tưởng và ý tưởng thiết kế chiến lược đầu cơ từ các chiến lược đầu cơ cổ điển nhất. Ngày nay, hoạt động của thị trường tiền kỹ thuật số cao hơn nhiều so với khi thị trường bắt đầu hình thành, và nhiều sàn giao dịch hợp đồng đã xuất hiện, cung cấp nhiều cơ hội đầu cơ ưu đãi.

  • Nguyên tắc chiến lược

    Tại sao nói chiến lược là một số hạt nhân cứng, lý do là chiến lược được viết bằng ngôn ngữ C ++, chiến lược khó đọc một chút. Nhưng không ngăn cản người đọc học các thiết kế chiến lược, ý tưởng. Về mặt thiết kế, các chiến lược có cấu trúc hợp lý, mật độ mã thấp, dễ mở rộng hoặc tối ưu hóa; suy nghĩ logic rõ ràng, các thiết kế như vậy không chỉ dễ sử dụng, dễ mở rộng; là một chiến lược giảng dạy, thiết kế chiến lược học tập cũng là một ví dụ tốt. Các nguyên tắc chiến lược tương đối đơn giản, đó là hợp đồng dài hạn và hợp đồng ngắn hạn, đối kháng, về cơ bản phù hợp với việc bảo hiểm dài hạn của hợp đồng tương lai hàng hóa. Trong khi đó, một người phụ nữ khác cũng có thể làm việc với một người đàn ông khác. Trong khi đó, các nhà lãnh đạo của các quốc gia khác cũng có thể tham gia vào các cuộc biểu tình này. Các nguyên tắc cơ bản đã rõ ràng, còn lại là chiến lược làm thế nào để kích hoạt đầu tư đầu cơ, làm thế nào để cân bằng, làm thế nào để tăng đầu tư. Chiến lược đầu cơ chủ yếu tập trung vào sự biến động của giá chênh lệch trên các mục tiêu, và giao dịch ngược về giá chênh lệch. Tuy nhiên, giá chênh lệch có thể có một sự biến động nhỏ, hoặc một sự biến động lớn, hoặc một chiều. Điều này mang lại sự không chắc chắn về lợi nhuận và lỗ hổng đầu cơ, nhưng rủi ro vẫn còn nhỏ hơn nhiều so với xu hướng đơn phương. Đối với các chiến lược dài hạn, nhiều tối ưu hóa khác nhau được lựa chọn từ mức kiểm soát vị trí, bắt đầu từ việc mở giao dịch. Ví dụ, sử dụng chỉ số Brinh cổ điển như là biến động giá chênh lệch, mở đầu, mở lại, điểm đặt chung. Chiến lược này được thiết kế hợp lý và có độ kết hợp thấp, và có thể dễ dàng được sửa đổi thành chiến lược đầu cơ dài hạn của chỉ số Brinh.

  • Phân tích mã chiến lược

    Có thể nói rằng, một cái nhìn ngắn gọn về mã, có thể kết luận rằng mã có thể được chia thành bốn phần.

    • Định nghĩa giá trị danh sách, định nghĩa một số giá trị trạng thái, được sử dụng để đánh dấu trạng thái. Một số hàm chức năng không liên quan đến ý tưởng chính sách, chẳng hạn như hàm mã hóa url, hàm chuyển đổi thời gian, v.v.
    • 2.K线数据生成器类:策略由该生成器类对象生成的K线数据驱动。
    • 3.对冲类:该类的对象可以执行具体的交易逻辑,对冲操作、策略细节的处理机制等。
    • 4.策略主函数,也就是 mainChức năng.mainChức năng là hàm đầu vào của chính sách, và các vòng lặp chính được thực hiện trong hàm này, ngoài ra, hàm này cũng thực hiện một hoạt động quan trọng, truy cập vào giao diện websocket của sàn giao dịch, lấy dữ liệu tick được đẩy, làm dữ liệu nguyên liệu của trình tạo dữ liệu K-line.

    Bằng cách hiểu toàn bộ mã chiến lược, chúng ta có thể học toàn bộ thiết kế, ý tưởng và kỹ thuật của chiến lược bằng cách phân tích từng chi tiết.

    • Định nghĩa giá trị liệt kê, các hàm chức năng khác

      Một, loại danh sáchStateTuyên bố

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

      Bởi vì một số hàm trong mã trả về một trạng thái, tất cả các trạng thái này được định nghĩa theo kiểu liệt kê.StateTrong đó có: Bạn có thể thấy nó xuất hiện trong mãSTATE_NANhững người bị ảnh hưởng là những người bị ảnh hưởng.STATE_IDLETrong trường hợp này, bạn có thể sử dụng các tính năng như:STATE_HOLD_LONGTrong khi đó, các nhà đầu tư khác cũng có thể tham gia vào các hoạt động này.STATE_HOLD_SHORTTình trạng nắm giữ các vị trí được bảo hiểm ngược.

      2, thay thế chuỗi, không có cuộc gọi trong chính sách này, là một chức năng công cụ dự phòng, chủ yếu xử lý chuỗi.

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

      3, hàm là hàm được chuyển đổi thành 16 chữ sốtoHex

      inline unsigned char toHex(unsigned char x)
      

      4, chức năng xử lý mã hóa url

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

      5, chức năng chuyển đổi thời gian, chuyển đổi thời gian của định dạng chuỗi thành thời gian.

      uint64_t _Time(string &s)
      
    • Loại máy tạo dữ liệu tuyến 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;
      };
      

      Loại này chủ yếu chịu trách nhiệm xử lý dữ liệu tick thu được thành các đường K chênh lệch để điều khiển chiến lược đầu cơ logic. Một số độc giả có thể có câu hỏi, tại sao nên sử dụng dữ liệu tick? Tại sao nên xây dựng một trình tạo dữ liệu K-line như vậy? Không tốt với dữ liệu K-line trực tiếp? Những câu hỏi này đã xuất hiện nhiều lần, và cũng đã xuất hiện khi tôi bắt đầu viết một số chiến lược đầu cơ. Trong khi đó, dữ liệu đường K của sự khác biệt giá của hai hợp đồng là thống kê thay đổi giá chênh lệch trong một khoảng thời gian nhất định, vì vậy không thể đơn giản lấy dữ liệu đường K của hai hợp đồng riêng biệt để thực hiện phép trừ, tính toán sự khác biệt của các dữ liệu trên mỗi đường K Bar, như giá chênh lệch. Sai lầm rõ ràng nhất là, ví dụ, giá cao nhất, giá thấp nhất của hai hợp đồng, không nhất thiết phải là cùng một thời điểm. Vì vậy, giá trị trừ ra không có ý nghĩa lớn. Do đó, chúng ta cần sử dụng dữ liệu tick trong thời gian thực, tính toán chênh lệch trong thời gian thực, thống kê thời gian thực về sự thay đổi giá trong một chu kỳ nhất định (tức là thu nhập cao và thấp trên cột đường K); vì vậy chúng ta cần một trình tạo dữ liệu đường K, riêng biệt như một lớp, tốt để xử lý sự tách rời logic.

    • Lớp đối kháng

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

      Do phần code khá dài, một phần đã bị bỏ qua, chủ yếu là để hiển thị cấu trúc của lớp bảo hiểm này, cấu trúc hàm Hedge không được nói đến, chủ yếu là khởi tạo đối tượng.

      • getState

        Chức năng này chủ yếu xử lý việc phát hiện lệnh, hủy lệnh, kiểm tra vị trí, cân bằng vị trí, v.v. Vì trong quá trình giao dịch rủi ro, không thể tránh được tình huống một chân (tức là một hợp đồng đã được giao dịch, một hợp đồng không được giao dịch), nếu kiểm tra trong logic đặt hàng, sau đó xử lý đơn hàng theo dõi hoặc cân bằng, logic chiến lược sẽ khá lộn xộn. Vì vậy, khi thiết kế phần này, một cách suy nghĩ khác đã được áp dụng. Nếu kích hoạt các hoạt động rủi ro, lần sau, cho dù xảy ra một chân là rủi ro, rủi ro mặc định đã thành công, sau đó kiểm tra cân bằng vị trí trong chức năng getState, độc lập kiểm tra logic xử lý cân bằng này.

      • Chuỗi

        Các chiến lược giao dịch logic được gói trong hàm này, trong đó các cuộc gọigetState, Sử dụng các đối tượng của trình tạo dữ liệu K-line để tạo ra dữ liệu K-line về chênh lệch giá, để đánh giá các giao dịch mở, ổn định, tăng giá; cũng có một số thao tác cập nhật dữ liệu trên biểu đồ.

    • Chức năng chính

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

      Sau khi khởi động, chính sách được thực hiện từ hàm main, trong quá trình khởi tạo của hàm main, chính sách đã đăng ký tick field của giao diện websocket. Nhiệm vụ chính của hàm main là xây dựng một vòng tròn chính, tiếp nhận liên tục các tick field từ giao diện websocket của sàn giao dịch, và sau đó gọi các hàm thành viên của đối tượng loại bảo hiểm: Loop function. Các logic giao dịch trong Loop function được điều khiển bởi dữ liệu giao dịch. Một điểm cần lưu ý là thị trường tick được đề cập ở trên, thực sự là giao diện dữ liệu chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết chi tiết Để biết thêm chi tiết, hãy xem chính sách làm thế nào để đăng ký dữ liệu giao diện websocket và cách thiết lập.

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

      Trước tiên, bạn cần mã hóa URL của thông báo đăng ký được truyền qua giao diện đăng ký bằng các tham số json, tức làpayloadGiá trị của tham số. Sau đó, một bước quan trọng hơn là gọi hàm giao diện API của nền tảng giao dịch định lượng của nhà phát minh.DialChức năng.DialCác chức năng có thể được sử dụng để truy cập vào giao dịch websocket giao diện. Chúng tôi đã thực hiện một số cài đặt để websocket sắp được tạo kết nối đối tượng điều khiển ws có kết nối tự động ngắt (tín hiệu đăng ký vẫn sử dụng payload tham số giá trị qs chuỗi), để thực hiện chức năng này cần phải cóDialThêm tùy chọn cấu hình vào chuỗi số tham số của hàm.

      DialPhần đầu tiên của tham số hàm là:

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

      là địa chỉ giao diện websocket cần truy cập, sau đó sử dụng|Phân biệt.compress=gzip_raw&mode=recv&reconnect=true&payload="+qsTất cả đều là các tham số cấu hình.

      Tên tham số Mô tả
      nén compress là chế độ nén, giao diện websocket OKEX sử dụng gzip_raw.
      chế độ mode là chế độ, có thể chọn dual, send, recv ba cách. dual là hai chiều, gửi dữ liệu nén, nhận dữ liệu nén. send để gửi dữ liệu nén. recv để nhận dữ liệu nén, giải nén cục bộ.
      kết nối lại reconnect cho xem có thiết lập nối lại hay không, reconnect=true cho bật nối lại, không đặt mặc định không nối lại.
      tải trọng Payload là một thông báo đăng ký cần được gửi khi kết nối lại với ws.

      Sau khi thiết lập như vậy, ngay cả khi kết nối websocket bị ngắt, các hệ thống dưới cùng của nhà quản lý sẽ tự động kết nối lại để có được dữ liệu thị trường mới nhất trong thời gian thích hợp. Trong khi đó, các nhà đầu tư cũng có thể sử dụng các công cụ như:

  • Kiểm soát vị trí

    Điều khiển vị trí sử dụng tỷ lệ vị thế được bảo hiểm tương tự như các hàng "Boffinach".

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

    Bạn có thể thấy rằng mỗi lần tăng số lượng các vị trí tăng giá là tổng của hai vị trí gần đây nhất. Việc kiểm soát vị trí như vậy có thể thực hiện khi chênh lệch lớn hơn, số lượng rủi ro lợi nhuận tương đối tăng, phân tán vị trí, do đó nắm bắt các vị trí nhỏ biến động chênh lệch nhỏ, các vị trí biến động chênh lệch lớn tăng lên một cách thích hợp.

  • Định giá ổn định: dừng lỗ dừng tăng

    Những người tham gia vào cuộc họp này đã nói rằng họ sẽ không làm điều gì sai trái. Chỉ cần giữ giá chênh lệch đến vị trí tăng, dừng lỗ, dừng lỗ.

  • Đưa ra thị trường, rời khỏi thị trường, thiết kế chu kỳ

    Các tham số NPeriod kiểm soát chu kỳ để kiểm soát một số động lực đối với chiến lược giao dịch mở.

  • Biểu đồ chiến lược

    Chiến lược tự động tạo ra biểu đồ đường K của chênh lệch, đánh dấu thông tin giao dịch liên quan.

    C++ chính sách tùy chỉnh biểu đồ vẽ biểu đồ hoạt động, cũng rất đơn giản, bạn có thể thấy trong các cấu trúc hàm của lớp đối kháng, chúng tôi đã sử dụng viết tốt biểu đồ cấu hình chuỗi_cfgStr cấu hình cho đồ thị đối tượng_c, _c là các thành viên riêng của lớp đối kháng được gọi khi khởi tạo các nhà phát minh định lượng tùy chỉnh biểu đồ API giao diện hàmChartCác đối tượng biểu đồ được cấu trúc bởi các hàm.

    _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();                         // 重置图表数据。
    
    • Gọi điện_c.update(_cfgStr);Sử dụng _cfgStr để cấu hình đối tượng biểu đồ.
    • Gọi điện_c.reset();Đặt lại dữ liệu biểu đồ.

    Khi mã chính sách cần chèn dữ liệu vào biểu đồ, nó cũng có thể được thực hiện bằng cách trực tiếp gọi hàm thành viên của đối tượng _c, hoặc chuyển đến tham chiếu của đối tượng _c như một tham số, sau đó gọi hàm thành viên của đối tượng _c để cập nhật dữ liệu biểu đồ, cài đặt các hoạt động. Ví dụ:

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

    Sau khi đặt hàng, ghi nhãn trên biểu đồ K-line.

    Dưới đây, vẽ các đường K là các hàm thành viên của lớp BarFeeder bằng cách gọifeedTrong khi đó, bạn có thể sử dụng một tham chiếu của đối tượng biểu đồ _c như là một tham số.

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

    Có nghĩa làfeedCác biến số c của hàm.

    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)。
        } 
    }
    

    Bằng cách gọi đối tượng biểu đồ _caddCác hàm thành viên để chèn dữ liệu K-lineBar mới vào biểu đồ. Mã là:c->add(chartIdx, point);

  • Kiểm tra lại

    img

    img

    img

Chính sách này chỉ được sử dụng để học trao đổi, khi sử dụng máy tính thực, hãy tự sửa đổi và tối ưu hóa theo tình huống thực tế của máy tính thực.

Địa chỉ chiến lược:https://www.fmz.com/strategy/163447

Các chiến thuật thú vị hơn được xem tại "Inventors Quantify Trading Platform":https://www.fmz.com


Có liên quan

Thêm nữa