Desain strategi lindung nilai spot cryptocurrency ((1)

Penulis:Lydia, Dibuat: 2022-08-16 10:30:56, Diperbarui: 2023-09-19 21:46:16

img

Desain strategi lindung nilai spot cryptocurrency ((1)

Strategi lindung nilai adalah strategi praktik yang sangat baik untuk pemula dalam desain strategi.

Merancang beberapa fungsi dan parameter antarmuka strategi sesuai dengan persyaratan strategi

Pertama-tama, jelas bahwa strategi yang akan dirancang adalah strategi lindung nilai spot cryptocurrency. Kami merancang strategi lindung nilai paling sederhana. 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 perbedaannya. Ketika bursa dengan harga yang lebih tinggi semua koin nominal (karena koin dengan harga yang lebih tinggi dijual), dan bursa dengan harga yang lebih rendah semua koin (koin dengan harga yang lebih rendah dibeli), itu tidak dapat dilindung nilai. Pada saat ini, kita hanya dapat menunggu pembalikan harga untuk lindung nilai.

Saat melakukan hedging, harga dan kuantitas order dibatasi oleh bursa, dan ada juga batas pada jumlah order minimum. Selain batas minimum, strategi dalam hedging juga perlu mempertimbangkan volume order maksimum pada satu waktu. Jika volume order terlalu besar, tidak akan ada volume order yang cukup. Juga perlu dipertimbangkan bagaimana mengubah nilai tukar jika dua koin yang berdenominasi bursa berbeda. Saat hedging, biaya penanganan dan slippage dari pemegang order adalah semua biaya transaksi, tidak selama ada perbedaan harga yang dapat dilindungi. Oleh karena itu, perbedaan harga hedging juga memiliki nilai pemicu. Jika lebih rendah dari perbedaan harga tertentu, hedging akan kehilangan.

Berdasarkan pertimbangan ini, strategi harus dirancang dengan beberapa parameter:

  • Perbedaan lindung nilai:hedgeDiffPrice, ketika selisihnya melebihi nilai ini, operasi lindung nilai dipicu.
  • Jumlah minimum lindung nilai:minHedgeAmount, jumlah pesanan minimum (koin) yang dapat dilindungi.
  • Jumlah maksimum lindung nilai:maxHedgeAmount, jumlah pesanan maksimum (koin) untuk satu lindung nilai.
  • Keakuratan harga A:pricePrecisionA, presisi harga order (jumlah desimal) yang ditempatkan oleh Exchange A.
  • Keakuratan jumlah A:amountPrecisionA, jumlah presisi pesanan yang ditempatkan oleh Exchange A (jumlah tempat desimal).
  • Keakuratan harga B:pricePrecisionB, presisi harga order (jumlah desimal) yang ditempatkan oleh Exchange B.
  • Keakuratan jumlah B:amountPrecisionB, jumlah presisi pesanan yang ditempatkan oleh Exchange B (jumlah tempat desimal).
  • Nilai tukar A:rateA, konversi nilai tukar dari objek pertukaran pertama yang ditambahkan, default adalah 1, tidak dikonversi.
  • Nilai tukar B:rateB, konversi nilai tukar dari objek pertukaran kedua yang ditambahkan, default adalah 1, tidak dikonversi.

Strategi lindung nilai perlu menjaga jumlah koin dalam dua akun tidak berubah (yaitu, tidak memegang posisi ke arah mana pun, dan menjaga netralitas), sehingga perlu ada logika keseimbangan dalam strategi untuk selalu mendeteksi keseimbangan.

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

Setelah menempatkan pesanan, jika tidak ada pesanan yang selesai, kita perlu membatalkannya tepat waktu, dan pesanan tidak dapat tetap menunggu. operasi ini perlu diproses baik dalam modul saldo dan logika lindung nilai, sehingga juga perlu untuk merancang fungsi penarikan pesanan penuh.

  • Batalkan Semua
    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)
                }
            }
        })
    }
    

Saat menyeimbangkan jumlah koin, kita perlu menemukan harga akumulasi untuk sejumlah koin dalam data kedalaman tertentu, jadi kita perlu fungsi seperti itu untuk menanganinya.

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

Kemudian kita perlu merancang dan menulis operasi pesanan lindung nilai tertentu, yang perlu dirancang untuk menempatkan pesanan bersamaan:

  • 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 desain fungsi keseimbangan, yang sedikit rumit.

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

Setelah mendesain fungsi-fungsi ini sesuai dengan persyaratan strategi, kemudian mulailah mendesain fungsi utama strategi.

Desain fungsi utama strategi

Di platform FMZ, strategi dilaksanakan darimainPada awalmainfungsi, kita harus melakukan beberapa pekerjaan inisialisasi strategi.

  • Nama objek pertukaran Karena banyak operasi dalam strategi harus menggunakan objek pertukaran, seperti mendapatkan penawaran pasar, menempatkan pesanan dan sebagainya. jadi akan rumit untuk menggunakan nama panjang setiap kali, tipnya adalah menggunakan nama sederhana sebagai gantinya, misalnya:

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

    Ini membuat lebih mudah untuk menulis kode nanti.

  • Nilai tukar, desain terkait presisi

      // 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 nilai tukarrateA, rateBditetapkan menjadi 1 (default adalah 1), yaitu,rateA != 1ataurateB != 1tidak akan memicu, sehingga konversi nilai tukar tidak akan ditetapkan.

  • Setel ulang semua data

    img

    Kadang-kadang perlu untuk menghapus semua log dan menghapus data yang tercatat ketika strategi dimulai.isReset, dan merancang kode reset di bagian inisialisasi strategi, misalnya:

      if (isReset) {   // When isReset is true, reset the data
          _G(null)
          LogReset(1)
          LogProfitReset()
          LogVacuum()
          Log("reset all data", "#FF0000")
      }
    
  • Memulihkan data akun awal, memperbarui data rekening arus Untuk menilai saldo, strategi perlu terus mencatat aset rekening awal untuk perbandingan dengan yang saat ini.nowAccsdigunakan untuk merekam data rekening current, menggunakan fungsi yang baru saja kita dirancangupdateAccsuntuk mendapatkan data akun dari bursa saat ini.initAccsdigunakan untuk mencatat status akun awal (jumlah koin, jumlah koin denominasi, dll pada bursa A dan B).initAccs, gunakan_G()fungsi untuk mengembalikan pertama (fungsi _G akan mencatat data secara terus menerus, dan dapat mengembalikan data yang tercatat lagi, lihat dokumentasi API untuk rincian: [link](https://www.fmz.com/api#_gk-v)), jika query tidak berhasil, gunakan informasi rekening current untuk menugaskan nilai dan_Gfungsi untuk merekam.

    Seperti kode berikut:

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

Logika perdagangan, loop utama dalam fungsi utama

Kode dalam loop utama adalah proses setiap putaran eksekusi logika strategi, yang dijalankan berulang kali untuk membentuk loop utama strategi.

  • Mendapatkan data pasar dan menilai validitas data pasar

          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 bisa melihat bahwa fungsi paralelexchange.Godari platform FMZ digunakan untuk membuat objek bersamaandepthARoutine, depthBRoutineyang disebutGetDepth()Ketika dua objek bersamaan ini dibuat,GetDepth()antarmuka dipanggil segera, dan kedua permintaan untuk data kedalaman dikirim ke pertukaran. Lalu hubungiwait()metode daridepthARoutine, depthBRoutineobjek untuk mendapatkan data kedalaman.
    Setelah mendapatkan data kedalaman, perlu untuk memeriksa data kedalaman untuk menentukan keabsahannya.continuepernyataan dipicu untuk mengeksekusi kembali loop 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
          }
    

    Dalam hal parameter, kami telah membuat desain seperti: parameter FMZ dapatpertunjukanataumenyembunyikanberdasarkan parameter, sehingga kita dapat membuat parameter untuk memutuskan apakah untuk menggunakanprice spread, atauspread ratio.

    img

    Sebuah parameterdiffAsPercentagetelah ditambahkan ke parameter antarmuka strategi. kedua pengaturan parameter lainnya untuk menunjukkan atau menyembunyikan berdasarkan parameter ini adalah:hedgeDiffPrice@!diffAsPercentage, yang ditampilkan ketikadiffAsPercentageadalah palsu.hedgeDiffPercentage@diffAsPercentage, yang ditampilkan ketikadiffAsPercentageBenar. Setelah desain ini, kami memeriksadiffAsPercentageparameter, yang merupakan kondisi pemicu lindung nilai berdasarkan rasio perbedaan harga.diffAsPercentageParameter diperiksa, lindung nilai dipicu oleh perbedaan harga.

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

    Kondisi pemicu lindung nilai adalah sebagai berikut:

    1. Memenuhi spread lindung nilai terlebih dahulu, dan hanya ketika spread order memenuhi parameter spread yang ditetapkan maka dapat dilindung nilai.
    2. Jumlah yang dapat dilindungi di pasar harus memenuhi jumlah lindung nilai minimum yang ditetapkan dalam parameter. Karena jumlah pesanan minimum yang dapat dibatasi oleh bursa yang berbeda, yang terkecil dari keduanya harus diambil.
    3. Aset dalam pertukaran operasi jual cukup untuk menjual, dan aset dalam pertukaran operasi beli cukup untuk membeli. Ketika kondisi ini terpenuhi, eksekusi fungsi lindung nilai untuk menempatkan pesanan lindung nilai.isTradeDi sini, jika lindung nilai dipicu, variabel diatur menjaditrueDan reset variabel globallastKeepBalanceTSke 0 (lastKeepBalanceTS digunakan untuk menandai timestamp dari operasi penyeimbangan terakhir, mengaturnya ke 0 akan memicu operasi penyeimbangan segera), dan kemudian membatalkan semua pesanan yang menunggu.
  • Operasi penyeimbangan

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

    Hal ini dapat dilihat bahwa fungsi keseimbangan dijalankan secara berkala, tetapi jikalastKeepBalanceTSJika nilai dari transaksi ini dihitung kembali ke 0 setelah operasi lindung nilai dipicu, maka operasi penyeimbangan akan segera dipicu.

  • Informasi bilah 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 terlalu rumit dalam desain. Ini menampilkan waktu saat ini, perbedaan harga dari Exchange A ke Exchange B dan perbedaan harga dari Exchange B ke Exchange A. Dan menampilkan spread target lindung nilai saat ini, data aset dari akun exchange A dan akun exchange B.

Penanganan pasangan perdagangan dengan mata uang yang berbeda

Dalam hal parameter, kami merancang nilai parameter nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilai nilaimainHal ini harus dicatat bahwaSetRateFungsi konversi nilai tukar harus dijalankan terlebih dahulu. Karena fungsi ini mempengaruhi dua aspek:

  • Konversi harga dalam semua data pasar, data pesanan, dan data posisi.
  • Konversi mata uang dalam aset rekening. Misalnya, pasangan perdagangan saat ini adalahBTC_USDT, satuan harga adalahUSDT, dan mata uang denominasi yang tersedia dalam aset rekening jugaUSDTJika saya ingin mengkonversi nilai ke CNY, aturexchange.SetRate(6.8)dalam kode untuk mengubah data yang diperoleh oleh semua fungsi di bawahexchangeobjek pertukaran ke CNY. Untuk mengkonversi ke mata uang denominasi apa, masukkannilai tukar dari mata uang denominasi saat ini ke mata uang denominasi targetuntukSetRate function.

Strategi lengkap:Strategi Hedging Spot dari Mata Uang yang Berbeda (Tutorial)


Berkaitan

Lebih banyak