Thiết kế chiến lược bảo hiểm tiền mặt cho tiền kỹ thuật số (1)

Tác giả:Giấc mơ nhỏ, Tạo: 2021-07-19 17:38:24, Cập nhật: 2023-09-20 10:35:16

img

Thiết kế chiến lược bảo hiểm tiền mặt cho tiền kỹ thuật số (1)

Đối với những người mới bắt đầu thiết kế chiến lược, các chiến lược đầu cơ là một chiến lược thực tập tốt. Bài viết này thực hiện một chiến lược đầu cơ tiền kỹ thuật số đơn giản nhưng thực tế, hy vọng sẽ giúp những người mới bắt đầu học một số kinh nghiệm thiết kế.

Thiết kế một số hàm, các tham số giao diện chính sách theo nhu cầu của chính sách

Trước tiên, hãy nói rõ rằng chiến lược sắp được thiết kế này là một chiến lược đầu cơ tiền mặt kỹ thuật số, chúng tôi đã thiết kế một cách đơn giản nhất, chỉ bán trên hai sàn giao dịch tiền mặt, mua trên sàn giao dịch thấp hơn để kiếm được chênh lệch.

Giá, số lượng, sàn giao dịch có giới hạn về độ chính xác khi đặt hàng, và cũng có giới hạn về số lượng đơn đặt hàng tối thiểu. Ngoài việc có giới hạn tối thiểu, chiến lược ngoài giới hạn tối thiểu trong việc bảo hiểm cũng phải xem xét số lượng đơn đặt hàng tối đa được đặt hàng một lần, nếu đơn đặt hàng quá lớn thì sẽ không có đủ số lượng đơn đặt hàng. Bạn cũng cần xem xét cách chuyển đổi tỷ giá ngoại hối nếu hai đồng tiền được giao dịch khác nhau.

Trên cơ sở những cân nhắc này, chiến lược cần thiết phải thiết kế một vài thông số:

  • Đánh giá chênh lệch:hedgeDiffPrice, Khi giá vượt quá giá trị này, kích hoạt hoạt động bảo hiểm.
  • Đánh giá tối thiểu:minHedgeAmountSố tiền được bảo hiểm là số tiền tối thiểu có thể được bảo hiểm.
  • Tối đa rủi ro:maxHedgeAmountSố tiền ký quỹ được tính theo số tiền ký quỹ.
  • Giá chính xác:pricePrecisionA, Định giá chính xác của giao dịch A (số số nhỏ) ⇒
  • A là độ chính xác đơn vị sau:amountPrecisionA, Đơn vị chính xác của sàn giao dịch A (số số nhỏ).
  • Giá B chính xác:pricePrecisionBĐịnh giá chính xác của sàn giao dịch B (độ số nhỏ)
  • B: Chọn số chính xác:amountPrecisionB, Đơn vị chính xác của sàn giao dịch B (số số nhỏ) ⇒
  • Giá hối đoái:rateA, Chuyển đổi tỷ giá đối tượng giao dịch đầu tiên được thêm vào, mặc định 1 không chuyển đổi.
  • Giá hối đoái của sàn B:rateB, chuyển đổi tỷ giá đối tượng giao dịch thứ hai được thêm vào, mặc định 1 không chuyển đổi.

Chiến lược chống rủi ro đòi hỏi phải giữ số tiền của hai tài khoản không thay đổi (tức là không nắm giữ bất kỳ vị trí hướng nào, giữ trung tính), vì vậy cần một logic cân bằng trong chiến lược luôn phát hiện cân bằng. Khi phát hiện cân bằng, chúng ta không thể tránh lấy dữ liệu tài sản của hai sàn giao dịch. Chúng ta cần viết một hàm để sử dụng.

  • cập nhậtAccs
    function updateAccs(arrEx) {
        var ret = []
        for (var i = 0 ; i < arrEx.length ; i++) {
            var acc = arrEx[i].GetAccount()
            if (!acc) {
                return null
            }
            ret.push(acc)
        }
        return ret 
    }
    

Nếu lệnh không được giao dịch sau đó, chúng ta cần hủy bỏ đúng thời điểm, không thể để lệnh bị treo. Hoạt động này đều cần được xử lý trong mô-đun cân bằng hoặc trong logic đầu cơ, vì vậy cần thiết phải thiết kế một hàm hủy bỏ toàn bộ lệnh.

  • hủy tất cả
    function cancelAll() {
        _.each(exchanges, function(ex) {
            while (true) {
                var orders = _C(ex.GetOrders)
                if (orders.length == 0) {
                    break
                }
                for (var i = 0 ; i < orders.length ; i++) {
                    ex.CancelOrder(orders[i].Id, orders[i])
                    Sleep(500)
                }
            }
        })
    }
    

Khi cân bằng số tiền, chúng ta cần tìm giá tích lũy đến số tiền nhất định trong một số dữ liệu sâu, vì vậy cần một hàm như vậy để xử lý.

  • getDepthPrice
    function getDepthPrice(depth, side, amount) {
        var arr = depth[side]
        var sum = 0
        var price = null
        for (var i = 0 ; i < arr.length ; i++) {
            var ele = arr[i]
            sum += ele.Amount
            if (sum >= amount) {
                price = ele.Price
                break
            }
        }
        return price
    }
    

Sau đó, chúng ta cần phải thiết kế và viết các hoạt động đặt hàng theo lệnh cụ thể, chúng ta cần thiết kế các lệnh theo dõi cùng nhau:

  • hàng rào
    function hedge(buyEx, sellEx, price, amount) {
        var buyRoutine = buyEx.Go("Buy", price, amount)
        var sellRoutine = sellEx.Go("Sell", price, amount)
        Sleep(500)
        buyRoutine.wait()
        sellRoutine.wait()
    }
    

Cuối cùng, chúng ta sẽ hoàn thành việc thiết kế các hàm cân bằng, các hàm cân bằng hơi phức tạp.

  • giữ cân bằng
    function keepBalance(initAccs, nowAccs, depths) {
        var initSumStocks = 0
        var nowSumStocks = 0 
        _.each(initAccs, function(acc) {
            initSumStocks += acc.Stocks + acc.FrozenStocks
        })
        _.each(nowAccs, function(acc) {
            nowSumStocks += acc.Stocks + acc.FrozenStocks
        })
      
        var diff = nowSumStocks - initSumStocks
        // 计算币差
        if (Math.abs(diff) > minHedgeAmount && initAccs.length == nowAccs.length && nowAccs.length == depths.length) {
            var index = -1
            var available = []
            var side = diff > 0 ? "Bids" : "Asks"
            for (var i = 0 ; i < nowAccs.length ; i++) {
                var price = getDepthPrice(depths[i], side, Math.abs(diff))
                if (side == "Bids" && nowAccs[i].Stocks > Math.abs(diff)) {
                    available.push(i)
                } else if (price && nowAccs[i].Balance / price > Math.abs(diff)) {
                    available.push(i)
                }
            }
            for (var i = 0 ; i < available.length ; i++) {
                if (index == -1) {
                    index = available[i]
                } else {
                    var priceIndex = getDepthPrice(depths[index], side, Math.abs(diff))
                    var priceI = getDepthPrice(depths[available[i]], side, Math.abs(diff))
                    if (side == "Bids" && priceIndex && priceI && priceI > priceIndex) {
                        index = available[i]
                    } else if (priceIndex && priceI && priceI < priceIndex) {
                        index = available[i]
                    }
                }
            }
            if (index == -1) {
                Log("无法平衡")            
            } else {
                // 平衡下单
                var price = getDepthPrice(depths[index], side, Math.abs(diff))
                if (price) {
                    var tradeFunc = side == "Bids" ? exchanges[index].Sell : exchanges[index].Buy
                    tradeFunc(price, Math.abs(diff))
                } else {
                    Log("价格无效", price)
                }
            }        
            return false
        } else if (!(initAccs.length == nowAccs.length && nowAccs.length == depths.length)) {
            Log("错误:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
            return true 
        } else {
            return true 
        }
    }
    

Sau khi thiết kế các hàm này theo nhu cầu của chính sách, bạn có thể bắt đầu thiết kế các hàm chính của chính sách.

Thiết kế hàm chính

Phương pháp trên FMZ là từmainChức năng bắt đầu thực hiện tại.mainTrong phần bắt đầu của hàm, chúng ta sẽ làm một số công việc khởi tạo chính sách.

  • Tên đối tượng giao dịch Vì nhiều hoạt động trong chiến lược được sử dụng cho các đối tượng giao dịch, chẳng hạn như lấy thị trường, đặt hàng, v.v. Vì vậy, việc sử dụng một tên dài mỗi lần sẽ rất khó khăn, mẹo nhỏ là thay thế bằng một tên đơn giản, ví dụ:

    var exA = exchanges[0]
    var exB = exchanges[1]
    

    Một số người cho rằng việc viết code sau đó sẽ dễ dàng hơn.

  • Định giá, thiết kế chính xác

      // 精度,汇率设置
      if (rateA != 1) {
          // 设置汇率A
          exA.SetRate(rateA)
          Log("交易所A设置汇率:", rateA, "#FF0000")
      }
      if (rateB != 1) {
          // 设置汇率B
          exB.SetRate(rateB)
          Log("交易所B设置汇率:", rateB, "#FF0000")
      }
      exA.SetPrecision(pricePrecisionA, amountPrecisionA)
      exB.SetPrecision(pricePrecisionB, amountPrecisionB)
    

    Nếu các thông số ngoại hốirateArateBCó cài đặt là 1 (bằng mặc định là 1), đó làrateA != 1HoặcrateB != 1Không kích hoạt, do đó không thiết lập chuyển đổi tỷ giá.

  • Đặt lại tất cả dữ liệu

    img

    Đôi khi, khi bắt đầu chính sách, bạn cần xóa tất cả các nhật ký, dữ liệu ghi trống. Bạn có thể thiết kế một tham số giao diện chính sách.isReset, sau đó thiết kế phần đặt lại mã được khởi tạo trong chính sách, ví dụ:

      if (isReset) {   // 当isReset为真时重置数据
          _G(null)
          LogReset(1)
          LogProfitReset()
          LogVacuum()
          Log("重置所有数据", "#FF0000")
      }
    
  • Khôi phục dữ liệu tài khoản ban đầu, cập nhật dữ liệu tài khoản hiện tại Để đánh giá sự cân bằng, chiến lược cần phải ghi lại liên tục tình hình tài sản tài khoản ban đầu được sử dụng và so sánh với hiện tại.nowAccsĐây là một biến được sử dụng để ghi lại dữ liệu tài khoản hiện tại bằng cách sử dụng các hàm mà chúng tôi vừa thiết kế.updateAccsNhìn vào tài khoản của các sàn giao dịch hiện tại.initAccsSử dụng để ghi lại tình trạng tài khoản ban đầu (dữ liệu về số tiền của sàn A và sàn B, số tiền được định giá, v.v.)initAccsSử dụng đầu tiên_G()Phục hồi chức năng ((_G) chức năng ghi lại dữ liệu vĩnh viễn và có thể quay lại dữ liệu đã ghi lại, xem tài liệu API:Liên kết), nếu không có truy vấn, hãy gán và sử dụng thông tin tài khoản hiện tại_GCác chức năng ghi chép.

    Ví dụ:

      var nowAccs = _C(updateAccs, exchanges)
      var initAccs = _G("initAccs")
      if (!initAccs) {
          initAccs = nowAccs
          _G("initAccs", initAccs)
      }
    

Logic giao dịch, vòng tròn chính trong hàm chính

Mã trong vòng tròn chính là quá trình mà logic chiến lược thực hiện mỗi vòng, và việc thực hiện lặp đi lặp lại liên tục tạo thành vòng tròn chính. Hãy xem xét các quá trình mà chương trình trong vòng tròn chính thực hiện mỗi lần.

  • Thu thập dữ liệu thị trường để đánh giá hiệu quả của dữ liệu thị trường

          var ts = new Date().getTime()
          var depthARoutine = exA.Go("GetDepth")
          var depthBRoutine = exB.Go("GetDepth")
          var depthA = depthARoutine.wait()
          var depthB = depthBRoutine.wait()
          if (!depthA || !depthB || depthA.Asks.length == 0 || depthA.Bids.length == 0 || depthB.Asks.length == 0 || depthB.Bids.length == 0) {
              Sleep(500)
              continue 
          }
    

    Ở đây bạn có thể thấy các hàm đồng thời sử dụng nền tảng FMZexchange.Go, tạo ra một cuộc gọiGetDepth()Đối tượng đồng thời của giao diệndepthARoutinedepthBRoutine│ Khi tạo hai đối tượng đồng thời, hãy gọiGetDepth()Một giao diện cũng xảy ra ngay lập tức, khi cả hai yêu cầu thu thập dữ liệu sâu được gửi đến sàn giao dịch. Sau đó gọidepthARoutinedepthBRoutineđối tượngwait()Cách thu thập dữ liệu sâu.
    Sau khi có được dữ liệu sâu, dữ liệu sâu cần được kiểm tra để đánh giá hiệu quả của nó.continueCâu nói thực hiện lại vòng tròn chính.

  • Sử dụng价差值Các tham số là差价比例Các tham số?

          var targetDiffPrice = hedgeDiffPrice
          if (diffAsPercentage) {
              targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
          }
    

    Các tham số của FMZ có thể dựa trên một số tham số.Hiển thịHoặcẩn náuVì vậy, chúng ta có thể làm cho một tham số để quyết định sử dụng价格差Hay là差价比例

    img

    Thêm một tham số vào tham số giao diện chiến lượcdiffAsPercentage❖ Hai tham số khác dựa trên tham số này hiển thị hoặc ẩn được đặt là:hedgeDiffPrice@!diffAsPercentageKhidiffAsPercentageĐể hiển thị tham số này.hedgeDiffPercentage@diffAsPercentageKhidiffAsPercentageTrả lời là đúng. Sau khi thiết kế xong, chúng tôi chọndiffAsPercentageCác tham số, đó là tỷ lệ chênh lệch giá như một điều kiện kích hoạt rủi ro; không chọndiffAsPercentageCác tham số là các điều kiện kích hoạt rủi ro theo giá khác nhau.

  • Xác định các điều kiện kích hoạt rủi ro

          if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) {          // A -> B 盘口条件满足            
              var price = (depthA.Bids[0].Price + depthB.Asks[0].Price) / 2
              var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
              if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance / price > minHedgeAmount) {
                  amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance / price, maxHedgeAmount)
                  Log("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks)  // 提示信息
                  hedge(exB, exA, price, amount)
                  cancelAll()
                  lastKeepBalanceTS = 0
                  isTrade = true 
              }            
          } else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPrice && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) {   // B -> A 盘口条件满足
              var price = (depthB.Bids[0].Price + depthA.Asks[0].Price) / 2
              var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
              if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance / price > minHedgeAmount) {
                  amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance / price, maxHedgeAmount)
                  Log("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks)  // 提示信息
                  hedge(exA, exB, price, amount)
                  cancelAll()
                  lastKeepBalanceTS = 0
                  isTrade = true 
              }            
          }
    

    Có một số điều kiện kích hoạt rủi ro như sau: 1, Đáp ứng đầu tiên với chênh lệch bảo hiểm, và chỉ có thể bảo hiểm khi chênh lệch của giao dịch đáp ứng các tham số chênh lệch được thiết lập. 2, giá trị giao dịch có thể được bảo hiểm đáp ứng giá trị bảo hiểm tối thiểu được đặt trên tham số, vì giá trị giao dịch tối thiểu có thể được giới hạn khác nhau, nên chọn giá trị tối thiểu của hai giá trị này. 3. Các tài sản trên sàn giao dịch bán hoạt động đủ để bán và các tài sản trên sàn giao dịch mua hoạt động đủ để mua. Khi các điều kiện này được đáp ứng, thực hiện các chức năng bảo hiểm để bảo hiểm. Trước chức năng chính, chúng ta đã tuyên bố một biến trước.isTradeĐể đánh dấu liệu có rủi ro xảy ra hay không, nếu rủi ro được kích hoạt, hãy đặt biến này làtrueVà đặt lại các biến toàn cầulastKeepBalanceTSĐể 0 (LastKeepBalanceTS được sử dụng để đánh dấu thời gian của hoạt động cân bằng gần đây, đặt vào 0 sẽ kích hoạt hoạt động cân bằng ngay lập tức), sau đó hủy tất cả các danh sách treo.

  • Hoạt động cân bằng

          if (ts - lastKeepBalanceTS > keepBalanceCyc * 1000) {
              nowAccs = _C(updateAccs, exchanges)
              var isBalance = keepBalance(initAccs, nowAccs, [depthA, depthB])
              cancelAll()
              if (isBalance) {
                  lastKeepBalanceTS = ts
                  if (isTrade) {
                      var nowBalance = _.reduce(nowAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
                      var initBalance = _.reduce(initAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
                      LogProfit(nowBalance - initBalance, nowBalance, initBalance, nowAccs)
                      isTrade = false 
                  }                
              }            
          }
    

    Bạn có thể thấy các hàm cân bằng sẽ được thực hiện thường xuyên, nhưng nếu sau khi kích hoạt các hoạt động đầu cơ, bạn sẽ thấy rằng các hàm cân bằng sẽ được thực hiện thường xuyên, nhưng nếu các hoạt động đầu cơ được kích hoạt sau khi kích hoạt, bạn sẽ thấy rằng các hàm cân bằng sẽ được thực hiện thường xuyên.lastKeepBalanceTSViệc cân bằng được đặt lại ở 0 sẽ được kích hoạt ngay lập tức. Sau khi cân bằng thành công, lợi nhuận sẽ được tính toán.

  • Thông tin trạng thái

          LogStatus(_D(), "A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, " B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, " targetDiffPrice:", targetDiffPrice, "\n", 
              "当前A,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n", 
              "当前B,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n", 
              "初始A,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n", 
              "初始B,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
    

    Các thanh trạng thái không có thiết kế phức tạp đặc biệt, hiển thị thời gian hiện tại, hiển thị chênh lệch giữa sàn giao dịch A và sàn giao dịch B và sàn giao dịch B với sàn giao dịch A.

Xử lý các cặp giao dịch với các đồng tiền khác nhau

Trong các tham số, chúng tôi đã thiết kế các tham số chuyển đổi giá trị tỷ giá để bắt đầu chiến lược.mainChúng tôi cũng đã thiết kế chuyển đổi tỷ giá. Điều cần lưu ý làSetRateChức năng chuyển đổi tỷ giá cần được thực hiện trước. Vì hàm này ảnh hưởng đến hai khía cạnh:

  • Tất cả dữ liệu thị trường, dữ liệu đơn đặt hàng, dữ liệu lưu trữ đều được chuyển đổi giá cả.
  • Việc đổi tiền trong tài sản tài khoản. Ví dụ, cặp giao dịch hiện tạiBTC_USDTCác đơn vị giá làUSDTCác tài sản tài khoản có thể được tính bằng tiền tệUSDTNếu tôi muốn chuyển đổi giá trị CNY, hãy đặt trong mã.exchange.SetRate(6.8)Chỉ cần đặtexchangeDữ liệu thu được của tất cả các hàm dưới đối tượng này được chuyển đổi thành CNY. Vì vậy, chúng ta sẽ có một số điều để làm.SetRatePhương thức truyền tảiGiá trị của đồng tiền hiện tại đối với đồng tiền mục tiêu

Chiến lược đầy đủ:Các chiến lược bảo hiểm hiện tại cho các loại tiền tệ khác nhau


Có liên quan

Thêm nữa

Squirrels là những loài sinh vật có sức sống rộng rãi.Thật tuyệt vời.