Reka bentuk strategi lindung nilai spot cryptocurrency ((1)

Penulis:Lydia, Dicipta: 2022-08-16 10:30:56, Dikemas kini: 2023-09-19 21:46:16

img

Reka bentuk strategi lindung nilai spot cryptocurrency ((1)

Strategi lindung nilai adalah strategi amalan yang sangat baik untuk pemula dalam reka bentuk strategi.

Merancang beberapa fungsi dan parameter antara muka strategi mengikut keperluan strategi

Pertama sekali, adalah jelas bahawa strategi yang akan direka adalah strategi lindung nilai mata wang kripto spot. Kami merancang strategi lindung nilai yang paling mudah. Kami menjual di bursa dengan harga yang lebih tinggi hanya antara dua bursa spot, dan membeli di bursa dengan harga yang lebih rendah untuk mengambil perbezaannya. Apabila bursa dengan harga yang lebih tinggi adalah semua duit syiling berdenominasi (kerana duit syiling dengan harga yang lebih tinggi dijual), dan bursa dengan harga yang lebih rendah adalah semua duit syiling (uang syiling dengan harga yang lebih rendah dibeli), ia tidak boleh dilindung nilai. Pada masa ini, kita hanya boleh menunggu pembalikan harga untuk lindung nilai.

Apabila lindung nilai, harga dan kuantiti pesanan adalah terhad oleh bursa, dan terdapat juga had pada kuantiti pesanan minimum. Selain had minimum, strategi dalam lindung nilai juga perlu mempertimbangkan jumlah pesanan maksimum pada satu masa. Jika jumlah pesanan terlalu besar, tidak akan ada jumlah pesanan yang mencukupi. Ia juga perlu mempertimbangkan bagaimana menukar kadar pertukaran jika dua duit syiling yang berdenominasi pertukaran berbeza. Semasa lindung nilai, yuran pengendalian dan slippage pemegang pesanan adalah semua kos transaksi, tidak selagi terdapat perbezaan harga boleh dilindung nilai. Oleh itu, perbezaan harga lindung nilai juga mempunyai nilai pemicu. Jika lebih rendah daripada perbezaan harga tertentu, lindung nilai akan hilang.

Berdasarkan pertimbangan ini, strategi perlu direka dengan beberapa parameter:

  • Perbezaan lindung nilai:hedgeDiffPrice, apabila perbezaan melebihi nilai ini, operasi lindung nilai dipicu.
  • Jumlah lindung nilai minimum:minHedgeAmount, jumlah pesanan minimum (matawang) yang boleh dilindungi.
  • Jumlah lindung nilai maksimum:maxHedgeAmount, jumlah pesanan maksimum (mata wang) untuk satu lindung nilai.
  • Ketepatan harga A:pricePrecisionA, ketepatan harga pesanan (bilangan tempat perpuluhan) yang diletakkan oleh Exchange A.
  • Kecekapan jumlah A:amountPrecisionA, jumlah ketepatan pesanan yang diletakkan oleh Exchange A (bilangan tempat perpuluhan).
  • Ketepatan harga B:pricePrecisionB, ketepatan harga pesanan (bilangan tempat perpuluhan) yang diletakkan oleh Exchange B.
  • Kecekapan jumlah B:amountPrecisionB, jumlah ketepatan pesanan yang diletakkan oleh Bursa B (bilangan tempat perpuluhan).
  • Kadar Pertukaran A:rateA, penukaran kadar pertukaran objek pertukaran pertama yang ditambah, lalai adalah 1, tidak ditukaran.
  • Kadar Pertukaran B:rateB, penukaran kadar pertukaran objek pertukaran kedua yang ditambah, lalai adalah 1, tidak ditukaran.

Strategi lindung nilai perlu mengekalkan jumlah syiling dalam kedua-dua akaun tidak berubah (iaitu, tidak memegang kedudukan ke arah mana-mana, dan mengekalkan netraliti), jadi perlu ada logik keseimbangan dalam strategi untuk sentiasa mengesan baki.

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

Selepas meletakkan pesanan, jika tidak ada pesanan yang selesai, kita perlu membatalkannya tepat pada masanya, dan pesanan tidak boleh disimpan menunggu. operasi ini perlu diproses dalam modul baki dan logik lindung nilai, jadi ia juga perlu untuk merancang fungsi pengeluaran pesanan penuh.

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

Apabila menyeimbangkan jumlah syiling, kita perlu mencari harga yang terkumpul kepada sebilangan syiling dalam data kedalaman tertentu, jadi kita memerlukan fungsi seperti itu untuk mengendalikannya.

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

Kemudian kita perlu merancang dan menulis operasi pesanan lindung nilai tertentu, yang perlu direka untuk meletakkan pesanan serentak:

  • perisai
    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()
    }
    

Akhirnya, mari kita selesaikan reka bentuk fungsi keseimbangan, yang agak rumit.

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

Selepas merancang fungsi ini mengikut keperluan strategi, kemudian mula merancang fungsi utama strategi.

Reka bentuk fungsi utama strategi

Di platform FMZ, strategi dilaksanakan darimainPada permulaanmainfungsi, kita perlu melakukan beberapa kerja inisialisasi strategi.

  • Nama objek pertukaran Oleh kerana banyak operasi dalam strategi harus menggunakan objek pertukaran, seperti mendapatkan sebut harga pasaran, meletakkan pesanan dan sebagainya.

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

    Ini memudahkan untuk menulis kod kemudian.

  • Kadar pertukaran, reka bentuk yang berkaitan dengan ketepatan

      // 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)
    

    Jika parameter kadar pertukaranrateA, rateBditetapkan kepada 1 (default adalah 1), iaitu,rateA != 1ataurateB != 1tidak akan mencetuskan, jadi penukaran kadar pertukaran tidak akan ditetapkan.

  • Tetapkan semula semua data

    img

    Kadang-kadang ia adalah perlu untuk memadamkan semua log dan membersihkan data yang direkodkan apabila strategi bermula.isReset, dan merancang kod reset dalam bahagian inisialisasi strategi, contohnya:

      if (isReset) {   // When isReset is true, reset the data
          _G(null)
          LogReset(1)
          LogProfitReset()
          LogVacuum()
          Log("reset all data", "#FF0000")
      }
    
  • Memulihkan data akaun asal, mengemas kini data akaun semasa Untuk menilai baki, strategi perlu terus mencatat aset akaun awal untuk perbandingan dengan yang semasa.nowAccsdigunakan untuk merakam data akaun semasa, menggunakan fungsi yang kita hanya direkaupdateAccsuntuk mendapatkan data akaun pertukaran semasa.initAccsdigunakan untuk merekodkan status akaun awal (bilangan syiling, bilangan syiling berdenominasi, dan lain-lain di bursa A dan B).initAccs, gunakan_G()fungsi untuk memulihkan terlebih dahulu (fungsi _G akan merakam data secara berterusan, dan boleh mengembalikan data yang direkodkan lagi, lihat dokumentasi API untuk butiran:www.fmz.com/api#_gk-v)), jika pertanyaan itu tidak berfungsi, gunakan maklumat akaun semasa untuk menetapkan nilai dan gunakan_Gfungsi untuk merekod.

    Seperti kod berikut:

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

Logik perdagangan, gelung utama dalam fungsi utama

Kod dalam gelung utama adalah proses setiap pusingan pelaksanaan logik strategi, yang dijalankan berulang kali untuk membentuk gelung utama strategi.

  • Dapatkan data pasaran dan menilai kesahihan data pasaran

          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 
          }
    

    Di sini kita boleh melihat bahawa fungsi serentakexchange.Godari platform FMZ digunakan untuk membuat objek serentakdepthARoutine, depthBRoutineyang memanggilGetDepth()Apabila kedua-dua objek serentak ini dicipta,GetDepth()Antara muka dipanggil dengan serta-merta, dan kedua-dua permintaan untuk data kedalaman dihantar ke pertukaran. Kemudian hubungiwait()kaedahdepthARoutine, depthBRoutineobjek untuk mendapatkan data kedalaman.
    Selepas mendapatkan data kedalaman, adalah perlu untuk memeriksa data kedalaman untuk menentukan kesahihannya.continuePerintah akan dicetuskan untuk menjalankan semula gelung utama.

  • Gunakanspread valueparameter atauspread ratioParameter?

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

    Dari segi parameter, kami telah membuat reka bentuk seperti: parameter FMZ bolehmenunjukkanataubersembunyiberdasarkan parameter, jadi kita boleh membuat parameter untuk memutuskan sama ada untuk menggunakanprice spread, atauspread ratio.

    img

    ParameterdiffAsPercentagetelah ditambah kepada parameter antara muka strategi. kedua-dua tetapan parameter lain untuk menunjukkan atau menyembunyikan berdasarkan parameter ini adalah:hedgeDiffPrice@!diffAsPercentage, yang dipaparkan apabiladiffAsPercentageadalah palsu.hedgeDiffPercentage@diffAsPercentage, yang dipaparkan apabiladiffAsPercentagememang benar. Selepas reka bentuk ini, kami memeriksadiffAsPercentageparameter, yang merupakan keadaan pencetus lindung nilai berdasarkan nisbah perbezaan harga.diffAsPercentageParameter diperiksa, lindung nilai diaktifkan oleh perbezaan harga.

  • Menentukan syarat pemicu lindung nilai

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

    Syarat pemicu lindung nilai adalah seperti berikut:

    1. Memenuhi penyebaran lindung nilai terlebih dahulu, dan hanya apabila penyebaran pesanan memenuhi parameter penyebaran yang ditetapkan ia boleh dilindung nilai.
    2. Jumlah yang boleh dilindungi di pasaran mesti memenuhi jumlah lindung nilai minimum yang ditetapkan dalam parameter.
    3. Aset dalam pertukaran operasi jual adalah cukup untuk menjual, dan aset dalam pertukaran operasi beli adalah cukup untuk membeli. Apabila syarat-syarat ini dipenuhi, menjalankan fungsi lindung nilai untuk meletakkan pesanan lindung nilai.isTradeDi sini, jika lindung nilai dicetuskan, pembolehubah ditetapkan kepadatrue. Dan menetapkan semula pembolehubah globallastKeepBalanceTSkepada 0 (lastKeepBalanceTS digunakan untuk menandakan cap masa operasi imbangan terakhir, menetapkannya kepada 0 akan mencetuskan operasi imbangan dengan segera), dan kemudian membatalkan semua pesanan yang menunggu.
  • Operasi menyeimbangkan

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

    Ia dapat dilihat bahawa fungsi penyeimbangan dijalankan secara berkala, tetapi jikalastKeepBalanceTSJika nilai semula ke 0 selepas operasi lindung nilai telah dicetuskan, operasi imbangan akan dicetuskan dengan serta-merta.

  • Maklumat bar status

          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)
    

    Bar status tidak begitu rumit dalam reka bentuk. Ia memaparkan masa semasa, perbezaan harga dari Bursa A ke Bursa B dan perbezaan harga dari Bursa B ke Bursa A. Dan ia memaparkan spread sasaran lindung nilai semasa, data aset akaun bursa A dan akaun bursa B.

Pengurusan pasangan dagangan mata wang yang berbeza

Dari segi parameter, kami merancang parameter nilai kadar penukaran, dan kami juga merancang penukaran kadar pertukaran dalam operasi awal sistem pengubahsuaian.mainIa harus diperhatikan bahawaSetRateFungsi penukaran kadar pertukaran perlu dilaksanakan terlebih dahulu. Kerana fungsi ini mempengaruhi dua aspek:

  • Penukaran harga dalam semua data pasaran, data pesanan, dan data kedudukan.
  • Penukaran mata wang dalam aset akaun. Sebagai contoh, pasangan dagangan semasa adalahBTC_USDT, unit harga adalahUSDT, dan mata wang yang tersedia dalam aset akaun jugaUSDT. Jika saya mahu menukar nilai ke CNY, menetapkanexchange.SetRate(6.8)dalam kod untuk menukar data yang diperoleh oleh semua fungsi di bawahexchangeobjek pertukaran kepada CNY. Untuk menukar kepada apa mata wang, masukkankadar pertukaran dari mata wang yang berdenominasi semasa kepada mata wang berdenominasi sasarankepadaSetRate function.

Strategi Lengkap:Strategi lindung nilai spot bagi mata wang yang berbeza (Tutorial)


Berkaitan

Lebih lanjut