Chiến lược phòng hộ giao ngay tiền điện tử (1)

Tác giả:Ninabadass, Tạo: 2022-04-14 11:57:46, Cập nhật: 2022-04-14 16:32:56

Chiến lược phòng hộ giao ngay tiền điện tử (1)

Đối với những người mới bắt đầu thiết kế chiến lược, chiến lược phòng hộ là một chiến lược rất tốt để thực hành.

Các chức năng thiết kế và tham số theo yêu cầu chiến lược

Trước hết, chúng ta cần đảm bảo rằng chiến lược được thiết kế là một chiến lược phòng hộ tại chỗ tiền điện tử. Chúng ta thiết kế phòng hộ đơn giản nhất. Chúng ta chỉ bán trên nền tảng với giá cao hơn giữa hai nền tảng tại chỗ, và mua trên nền tảng với giá thấp hơn để kiếm được chênh lệch giá. Khi nền tảng có giá cao hơn đầy các biểu tượng tiền tệ báo giá (vì giá cao, tất cả các biểu tượng tiền tệ được bán), hoặc khi nền tảng có giá thấp hơn đầy các biểu tượng tiền tệ (vì giá thấp, các biểu tượng tiền tệ được mua bởi tất cả các tài sản), nó không thể được bảo hiểm. Tại thời điểm này, bạn chỉ có thể chờ giá đảo ngược để phòng hộ.

Đối với giá lệnh và số tiền trong quá trình phòng ngừa rủi ro, có giới hạn độ chính xác trong mọi nền tảng, và cũng có giới hạn về số tiền đặt hàng tối thiểu. Ngoài giới hạn tối thiểu, chiến lược cũng cần xem xét số tiền đặt hàng tối đa cho một phòng ngừa rủi ro. Nếu số tiền đặt hàng quá lớn, thị trường sẽ không có khối lượng đơn đặt hàng đủ cho điều đó. Cũng cần phải xem xét cách chuyển đổi tỷ giá hối đoái nếu hai nền tảng có đồng tiền báo giá khác nhau. Phí xử lý trong quá trình phòng ngừa rủi ro và trượt của người nhận lệnh là tất cả các chi phí giao dịch. Bảo hiểm không phải lúc nào cũng xảy ra miễn là có sự khác biệt giá. Do đó, chênh lệch giá phòng ngừa rủi ro cũng có giá trị kích hoạt. Nếu nó thấp hơn một mức chênh lệch giá nhất định, phòng ngừa rủi ro sẽ gây ra lỗ.

Dựa trên điều đó, chiến lược cần phải được thiết kế với một số thông số:

  • Phân phối phòng hộ:hedgeDiffPriceKhi chênh lệch vượt quá giá trị, một phòng ngừa rủi ro sẽ được kích hoạt.
  • Số tiền bảo hiểm tối thiểu:minHedgeAmount, số tiền đặt hàng tối thiểu (tỷ lệ biểu tượng) có sẵn để phòng hộ.
  • Số tiền bảo hiểm tối đa:maxHedgeAmount, số tiền lệnh tối đa (tỷ lệ biểu tượng) có sẵn cho một phòng ngừa rủi ro.
  • Độ chính xác giá A:pricePrecisionA, độ chính xác giá lệnh (dữ số thập phân) của nền tảng A.
  • Độ chính xác số tiền đặt hàng A:amountPrecisionA, độ chính xác số lượng đơn đặt hàng (dấu số thập phân) của nền tảng A.
  • Độ chính xác giá B:pricePrecisionB, độ chính xác giá lệnh (dữ số thập phân) của nền tảng B.
  • Chi tiết số tiền đặt hàng B:amountPrecisionB, độ chính xác số lượng đơn đặt hàng (dấu số thập phân) của nền tảng B.
  • Giá hối đoái A:rateA, tỷ giá hối đoái chuyển đổi đối tượng hối đoái đầu tiên được thêm vào; mặc định là 1, chỉ ra không chuyển đổi.
  • Giá hối đoái B:rateB, tỷ giá hối đoái chuyển đổi đối tượng hối đoái thứ hai được thêm vào; mặc định là 1, chỉ ra không chuyển đổi.

Chiến lược phòng hộ cần giữ số tiền biểu tượng tiền tệ của hai tài khoản không thay đổi (tức là không giữ bất kỳ vị trí định hướng nào và duy trì trung lập), vì vậy cần có một logic cân bằng trong chiến lược để luôn phát hiện ra số dư. Khi kiểm tra số dư, không thể tránh được việc lấy dữ liệu tài sản từ hai nền tảng. Do đó, Chúng tôi 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 
    }
    

Sau khi đặt một lệnh, nếu không có lệnh được thực hiện, chúng ta cần phải hủy nó kịp thời, và lệnh không thể được giữ chờ.

  • 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ố lượng các biểu tượng tiền tệ, chúng ta cần tìm giá với một số lượng nhất định trong một dữ liệu độ sâu nhất định, vì vậy chúng ta cần một hàm như thế này để xử lý nó.

  • 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 thiết kế và viết các hoạt động lệnh bảo hiểm cụ thể, mà cần phải được thiết kế để đồng thời đặt lệnh:

  • 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, hãy hoàn thành thiết kế của hàm cân bằng, phức tạp hơn một chút.

  • 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
        // calculate currency spread 
        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("cannot balance")            
            } else {
                // balanced ordering 
                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("invalid price", price)
                }
            }        
            return false
        } else if (!(initAccs.length == nowAccs.length && nowAccs.length == depths.length)) {
            Log("error:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
            return true 
        } else {
            return true 
        }
    }
    

Các chức năng này đã được thiết kế theo các yêu cầu của chiến lược, và chúng ta có thể bắt đầu thiết kế chức năng chính của chiến lược.

Chiến lược Thiết kế chức năng chính

Trên FMZ, chiến lược được thực hiện từmainCác chức năngmainchức năng, chúng ta cần phải làm một số khởi tạo của chiến lược.

  • Tên đối tượng Exchange Đối với nhiều hoạt động trong chiến lược sử dụng đối tượng trao đổi, chẳng hạn như nhận được báo giá thị trường, đặt đơn đặt hàng, v.v. Vì vậy, nó sẽ không thuận tiện để sử dụng một tên dài hơn mỗi lần, mẹo nhỏ của tôi là sử dụng một tên ngắn đơn giản thay thế, ví dụ:

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

    Sau đó, nó sẽ thoải mái hơn để viết mã sau.

  • Tỷ giá hối đoái và độ chính xác

      // settings of precision and exchange rate
      if (rateA != 1) {
          // set exchange rate A 
          exA.SetRate(rateA)
          Log("Platform A sets exchange rate:", rateA, "#FF0000")
      }
      if (rateB != 1) {
          // set exchange rate B
          exB.SetRate(rateB)
          Log("Platform B sets exchange rate:", rateB, "#FF0000")
      }
      exA.SetPrecision(pricePrecisionA, amountPrecisionA)
      exB.SetPrecision(pricePrecisionB, amountPrecisionB)
    

    Nếu một trong các thông số tỷ giá hối đoái, cụ thể làrateArateB, được thiết lập là 1 (bên mặc định là 1), tức là,rateA != 1hoặcrateB != 1có nghĩa là không được kích hoạt và tỷ giá hối đoái không thể chuyển đổi.

  • Đặt lại tất cả ngày

    img

    Đôi khi, nó là cần thiết để xóa tất cả các nhật ký và hút bụi các bản ghi dữ liệu khi chiến lược được bắt đầu.isReset, và sau đó thiết kế mã thiết lập lại trong phần khởi tạo chiến lược, ví dụ:

      if (isReset) {   // when "isReset" is true, reset the data 
          _G(null)
          LogReset(1)
          LogProfitReset()
          LogVacuum()
          Log("Reset all data", "#FF0000")
      }
    
  • Khôi phục dữ liệu tài khoản ban đầu và cập nhật dữ liệu tài khoản hiện tại Để đánh giá số dư, chiến lược cần liên tục ghi lại điều kiện tài sản tài khoản ban đầu để so sánh với hiện tại.nowAccsđược sử dụng để ghi lại dữ liệu tài khoản vãng lai.updateAccschức năng mà chúng tôi vừa thiết kế để lấy dữ liệu tài khoản của nền tảng hiện tại.initAccsđược sử dụng để ghi lại tình trạng tài khoản ban đầu (dữ liệu như số tiền biểu tượng tiền tệ của cả A và B, số tiền báo giá, v.v.).initAccs, đầu tiên sử dụng_G()chức năng để khôi phục (công thức _G sẽ ghi lại dữ liệu liên tục, và có thể trả lại dữ liệu được ghi lại một lần nữa; đọc tài liệu API để biết chi tiết:liên kết).
    Nếu bạn không thể truy vấn dữ liệu, sử dụng thông tin tài khoản hiện tại để gán và sử dụng_G()chức năng để ghi lại.

    Ví dụ như mã sau:

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

Logic giao dịch, vòng lặp chính trong chức năng chính

Mã trong vòng lặp chính là quá trình của mỗi vòng thực thi logic chiến lược, và việc thực thi lặp lại không ngừng xây dựng vòng lặp chính chiến lược.

  • Nhận được các báo giá thị trường và đánh giá tính hợp lệ

          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 rằng hàm đồng thờiexchange.Gocủa nền tảng FMZ được sử dụng để tạo các đối tượng đồng thờidepthARoutinedepthBRoutinemà gọi làGetDepth()Khi hai đối tượng đồng thời này được tạo ra, cácGetDepth()giao diện được gọi ngay lập tức, và cả hai yêu cầu cho dữ liệu độ sâu được gửi đến nền tảng. Vậy gọi chowait()phương pháp đối tượngdepthARoutinevà đối tượngdepthBRoutineđể thu thập dữ liệu độ sâu. Sau khi thu thập dữ liệu độ sâu, cần phải kiểm tra dữ liệu độ sâu để đánh giá tính hợp lệ của nó.continuelệnh được kích hoạt để thực hiện lại vòng lặp chính.

  • Sử dụngprice spreadhoặcspread ratio?

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

    Về các thông số, chúng tôi đã thực hiện một thiết kế như vậy.biểu diễnhoặcẩndựa trên một tham số, vì vậy chúng ta có thể làm cho một tham số để quyết định xem có nên sử dụngprice spread, hoặcspread ratio.

    img

    Các thông sốdiffAsPercentageđã được thêm vào các thông số của giao diện chiến lược. hai thông số khác, mà sẽ hiển thị hoặc ẩn dựa trên các thông số được thiết lập như sau:hedgeDiffPrice@!diffAsPercentageKhi nàodiffAsPercentagelà sai, nó sẽ được hiển thị.hedgeDiffPercentage@diffAsPercentageKhi nàodiffAsPercentagelà đúng, nó sẽ được hiển thị.
    Sau khi thiết kế, chúng tôi đã kiểm tradiffAsPercentageĐiều kiện kích hoạt phòng ngừa rủi ro.diffAsPercentageNếu tham số này không được kiểm tra, giá chênh lệch được sử dụng làm điều kiện kích hoạt phòng ngừa rủi ro.

  • Thẩm phán Hedge Trigger

          if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) {          // A -> B market condition satisfied             
              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("triggerA->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks)  // prompt message 
                  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 market condition satisfied 
              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("triggerB->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks)  // prompt message
                  hedge(exA, exB, price, amount)
                  cancelAll()
                  lastKeepBalanceTS = 0
                  isTrade = true 
              }            
          }
    

    Có một số điều kiện kích hoạt để phòng ngừa rủi ro: 1.Đầu tiên, đáp ứng chênh lệch phòng ngừa rủi ro; chỉ khi chênh lệch thị trường đáp ứng tham số chênh lệch được thiết lập, việc bảo hiểm có thể xảy ra.

    2.Tổng bảo hiểm của thị trường nên đáp ứng số tiền bảo hiểm tối thiểu được thiết lập trong các tham số.

    3.Các tài sản trong nền tảng với hoạt động bán là đủ để bán, và các tài sản trong nền tảng với hoạt động mua là đủ để mua. Khi các điều kiện này được đáp ứng, thực hiện chức năng phòng ngừa để đặt lệnh theo phòng ngừa. Trước chức năng chính, chúng tôi tuyên bố một biếnisTradeỞ đây, nếu việc bảo hiểm được kích hoạt, biến được đặt thànhtrue. Và đặt lại biến toàn cầulastKeepBalanceTSđến 0 (lastKeepBalanceTS được sử dụng để đánh dấu dấu thời gian của hoạt động cân bằng cuối cùng, và đặt nó thành 0 sẽ kích hoạt hoạt động cân bằng ngay lập tức), và sau đó hủy tất cả các lệnh đang chờ.

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

    Có thể thấy rằng chức năng cân bằng được thực hiện định kỳ, nhưng nếulastKeepBalanceTSđược đặt lại 0 sau khi hoạt động phòng ngừa được kích hoạt, hoạt động cân bằng 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 thanh 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", 
              "currentA,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n", 
              "currentB,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n", 
              "initialA,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n", 
              "initialB,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
    

    Thanh trạng thái không được thiết kế để đặc biệt phức tạp. Nó hiển thị thời gian hiện tại, mức giá chênh lệch từ nền tảng A đến nền tảng B cũng như mức giá chênh lệch từ B đến A; nó cũng hiển thị mức chênh lệch mục tiêu bảo hiểm hiện tại, dữ liệu tài sản tài khoản của nền tảng A và dữ liệu tài sản tài khoản của nền tảng B.

Xử lý cặp giao dịch cho các loại tiền tệ báo giá khác nhau

Về các thông số, chúng tôi đã thiết kế các thông số chuyển đổi giá trị tỷ giá hối đoái, và chúng tôi cũng đã thiết kế chuyển đổi tỷ giá hối đoái trong hoạt động ban đầu củamainNên lưu ý rằngSetRateChức năng chuyển đổi tỷ giá hối đoái cần được thực hiện trước tiên.

Đối với chức năng sẽ ảnh hưởng đến hai khía cạnh:

  • Chuyển đổi giá trong tất cả dữ liệu báo giá thị trường, dữ liệu đơn đặt hàng và dữ liệu vị trí.
  • Chuyển đổi tiền tệ báo giá thành tài sản tài khoản.

Ví dụ, cặp giao dịch hiện tại làBTC_USDT, đơn vị giá làUSDT, và đồng tiền báo giá có sẵn trong tài sản tài khoản cũng làUSDTNếu tôi muốn chuyển đổi giá trị tài sản thành CNY, đặtexchange.SetRate(6.8)trong mã để chuyển đổi dữ liệu thu được bởi tất cả các chức năng theoexchangeđối tượng, và sau đó chuyển đổi thành CNY. Để chuyển đổi sang tiền tệ báo giá, nhập khẩutỷ giá hối đoái từ đồng tiền báo giá hiện tại sang đồng tiền báo giá mục tiêuvàoSetRate function.

Chiến lược hoàn chỉnh:Chiến lược phòng hộ tại chỗ của các loại tiền tệ báo giá khác nhau (Giảng dạy)


Thêm nữa