Thiết kế chiến lược phòng ngừa rủi ro giao ngay tiền điện tử ((1)

Tác giả:Lydia., Tạo: 2022-08-16 10:30:56, Cập nhật: 2023-09-19 21:46:16

img

Thiết kế chiến lược phòng ngừa rủi ro giao ngay tiền điện tử ((1)

Chiến lược phòng ngừa rủi ro là một chiến lược thực hành rất tốt cho người mới bắt đầu trong thiết kế chiến lược.

Thiết kế một số chức năng và các thông số giao diện chiến lược theo các yêu cầu chiến lược

Trước hết, rõ ràng 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 tôi thiết kế chiến lược phòng hộ đơn giản nhất. Chúng tôi bán trên sàn giao dịch với giá cao hơn chỉ giữa hai sàn giao dịch tại chỗ, và mua trên sàn giao dịch với giá thấp hơn để lấy sự khác biệt. Khi các sàn giao dịch có giá cao hơn đều là đồng xu danh nghĩa (vì các đồng xu có giá cao hơn được bán), và các sàn giao dịch có giá thấp hơn là tất cả các đồng xu (những đồng xu có giá thấp hơn được mua), nó không thể được bảo hiểm. Tại thời điểm này, chúng tôi chỉ có thể chờ đợi sự đảo ngược giá để bảo hiểm.

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

Dựa trên những cân nhắc này, chiến lược cần phải được thiết kế với một số thông số:

  • Sự khác biệt bảo hiểm:hedgeDiffPrice, khi chênh lệch vượt quá giá trị này, hoạt động phòng ngừa rủi ro đượ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ài tiền) có thể được bảo hiểm.
  • Số tiền bảo hiểm tối đa:maxHedgeAmount, số tiền đặt hàng tối đa (tiền xu) cho một lần phòng ngừa rủi ro.
  • Độ chính xác giá của A:pricePrecisionA, độ chính xác giá lệnh (số vị trí thập phân) được đặt bởi Exchange A.
  • Độ chính xác của A:amountPrecisionA, số tiền chính xác của lệnh được đặt bởi Exchange A (số vị trí thập phân).
  • Độ chính xác giá của B:pricePrecisionB, độ chính xác giá lệnh (số vị trí thập phân) được đặt bởi Exchange B.
  • Độ chính xác của B:amountPrecisionB, số tiền chính xác của lệnh được đặt bởi Exchange B (số vị trí thập phân).
  • Tỷ giá hối đoái A:rateA, chuyển đổi tỷ giá hối đoái của đối tượng hối đoái đầu tiên được thêm vào, mặc định là 1, không chuyển đổi.
  • Tỷ giá hối đoái B:rateB, chuyển đổi tỷ giá hối đoái của đối tượng hối đoái thứ hai được thêm vào, mặc định là 1, không chuyển đổi.

Chiến lược phòng ngừa rủi ro cần giữ số lượng tiền xu trong hai tài khoản không thay đổi (tức là không giữ vị trí theo bất kỳ hướng nào và duy trì tính 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 sự cân bằng. Khi kiểm tra sự cân bằng, không thể tránh được việc lấy dữ liệu tài sản từ 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 
    }
    

Sau khi đặt lệnh, nếu không có lệnh hoàn thành, chúng tôi 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ố tiền xu, chúng ta cần tìm giá tích lũy cho một số tiền xu nhất định trong một dữ liệu độ sâu nhất định, vì vậy chúng ta cần một chức năng như vậ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ế để đặt lệnh đồng thời:

  • 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, một chút 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
        // Calculate the currency difference
        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("unable to balance")            
            } else {
                // balance order
                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("errors:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
            return true 
        } else {
            return true 
        }
    }
    

Sau khi thiết kế các chức năng này theo các yêu cầu chiến lược, sau đó bắt đầu thiết kế chức năng chính của chiến lược.

Thiết kế chức năng chính của chiến lược

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

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

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

    Điều này làm cho nó dễ dàng hơn để viết mã sau này.

  • Giá hối đoái, thiết kế liên quan đến độ chính xác

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

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

  • Lập lại tất cả dữ liệu

    img

    Đôi khi nó là cần thiết để xóa tất cả các nhật ký và xóa các dữ liệu được ghi lại khi chiến lược bắt đầu.isReset, và thiết kế mã thiết lập lại trong phần khởi tạo của 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, 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 phải ghi lại liên tục các tài sản tài khoản ban đầu để so sánh với tài sản hiện tại.nowAccsđược sử dụng để ghi lại các dữ liệu tài khoản vãng lai, sử dụng các chức năng chúng tôi vừa thiết kếupdateAccsđể có được dữ liệu tài khoản của sàn giao dịch hiện tại.initAccsđược sử dụng để ghi lại tình trạng tài khoản ban đầu (số lượng tiền xu, số lượng tiền xu được mệnh giá, v.v. trên sàn giao dịch A và B).initAccs, sử dụng_G()chức năng để khôi phục đầu tiên (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, xem tài liệu API để biết chi tiết: [link](https://www.fmz.com/api#_gk-v)), nếu truy vấn không hoạt động, sử dụng thông tin tài khoản vãng lai để gán giá trị và sử dụng_Gchứ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, được thực hiện nhiều lần để tạo thành vòng lặp chính của chiến lược.

  • Thu thập dữ liệu thị trường và đánh giá tính hợp lệ 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 chúng ta 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ờidepthARoutine, depthBRoutinemà gọi làGetDepth()Khi hai đối tượng đồng thời này được tạo ra,GetDepth()giao diện được gọi ngay lập tức, và cả hai yêu cầu về dữ liệu độ sâu được gửi đến trao đổi. Vậy gọi chowait()phương phápdepthARoutine, depthBRoutineđối tượng để 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 để xác định 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ụngspread valuetham số hoặcspread ratioĐịa chỉ?

          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: các thông số của FMZ có thể đượcbiể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

    Một tham sốdiffAsPercentageđã được thêm vào các thông số của giao diện chiến lược. Hai cài đặt thông số khác để hiển thị hoặc ẩn dựa trên thông số này là:hedgeDiffPrice@!diffAsPercentage, được hiển thị khidiffAsPercentagelà sai.hedgeDiffPercentage@diffAsPercentage, được hiển thị khidiffAsPercentagelà sự thật. Sau khi thiết kế này, chúng tôi kiểm tradiffAsPercentageĐiều kiện kích hoạt phòng hộ dựa trên tỷ lệ chênh lệch giá.diffAsPercentagetham số được kiểm tra, phòng ngừa rủi ro được kích hoạt bởi sự khác biệt giá.

  • Xác định các điều kiện kích hoạt phòng ngừa 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 market conditions are met            
              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("trigger A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks)  // Tips
                  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 conditions are met
              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("trigger B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks)  // Tips
                  hedge(exA, exB, price, amount)
                  cancelAll()
                  lastKeepBalanceTS = 0
                  isTrade = true 
              }            
          }
    

    Các điều kiện kích hoạt phòng ngừa rủi ro là như sau:

    1. Đáp ứng chênh lệch phòng ngừa đầu tiên, và chỉ khi chênh lệch của lệnh đáp ứng các tham số chênh lệch được thiết lập, nó có thể được bảo hiểm.
    2. Số tiền có thể được bảo hiểm trên thị trường phải đáp ứng số tiền bảo hiểm tối thiểu được thiết lập trong các tham số. Bởi vì số tiền đặt hàng tối thiểu có thể được giới hạn bởi các sàn giao dịch khác nhau là khác nhau, nên lấy nhỏ nhất trong hai.
    3. Các tài sản trong trao đổi của hoạt động bán đủ để bán, và các tài sản trong trao đổi của hoạt động mua đủ để 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 một lệnh phòng ngừa.isTradeỞ đâ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, đặ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. Lợi nhuận sẽ được tính sau khi cân bằng thành công.

  • 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", 
              "current A, Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n", 
              "current B, Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n", 
              "initial A, Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n", 
              "initial 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 biệt phức tạp trong thiết kế. Nó hiển thị thời gian hiện tại, sự khác biệt giá từ Sàn giao dịch A đến Sàn giao dịch B và sự khác biệt giá từ Sàn giao dịch B đến Sàn giao dịch A. Và nó hiển thị hiện tại phòng hộ mục tiêu chênh lệch, dữ liệu tài sản của sàn giao dịch A tài khoản và sàn giao dịch B tài khoản.

Việc xử lý các cặp giao dịch bằng các loại tiền tệ khác nhau

Về các tham số, chúng tôi thiết kế tham số giá trị tỷ giá chuyển đổi, và chúng tôi cũng thiết kế tỷ giá chuyển đổ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. Bởi vì chức năng này ảnh hưởng đến hai khía cạnh:

  • Chuyển đổi giá trong tất cả dữ liệu thị trường, dữ liệu đơn đặt hàng và dữ liệu vị trí.
  • Chuyển đổi tiền tệ trong 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à số tiền 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ị 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 đối tượng sang CNY. Để chuyển đổi sang loại tiền tệ nào, chuyển vàotỷ giá hối đoái từ đồng tiền hiện tại thành đồng tiền mục tiêuđếnSetRate function.

Chiến lược hoàn chỉnh:Chiến lược phòng ngừa rủi ro tại chỗ của các loại tiền tệ khác nhau (Hướng dẫn)


Có liên quan

Thêm nữa