Strategi Hedge Spot Cryptocurrency (1)

Penulis:Ninabadass, Dibuat: 2022-04-14 11:57:46, Diperbarui: 2022-04-14 16:32:56

Strategi Hedge Spot Cryptocurrency (1)

Untuk pemula dalam merancang strategi, strategi lindung nilai adalah yang sangat baik untuk praktek.

Fungsi Desain & Parameter oleh Keperluan Strategi

Pertama-tama, kita perlu memastikan bahwa strategi yang akan dirancang adalah strategi lindung nilai spot cryptocurrency. Kami merancang lindung nilai yang paling sederhana. Kami hanya menjual di platform dengan harga yang lebih tinggi antara dua platform spot, dan membeli di platform dengan harga yang lebih rendah untuk mendapatkan spread harga. Ketika platform dengan harga yang lebih tinggi penuh dengan simbol mata uang kutipan (karena harga tinggi, semua simbol mata uang dijual), atau ketika platform dengan harga yang lebih rendah penuh dengan simbol mata uang (karena harga rendah, simbol mata uang dibeli oleh semua aset), itu tidak dapat dilindung nilai. Pada saat ini, Anda hanya dapat menunggu harga terbalik untuk lindung nilai.

Untuk harga pesanan dan jumlah saat lindung nilai, ada batas presisi di setiap platform, dan juga ada batas pada jumlah pesanan minimum. Selain batas minimum, strategi juga perlu mempertimbangkan jumlah pesanan maksimum untuk lindung nilai. Jika jumlah pesanan terlalu besar, pasar tidak akan memiliki volume pesanan yang cukup untuk itu. Juga perlu dipertimbangkan bagaimana mengubah nilai tukar jika kedua platform memiliki mata uang kutipan yang berbeda. Biaya penanganan selama lindung nilai dan tergelincirnya pemegang pesanan adalah semua biaya perdagangan. lindung nilai tidak selalu terjadi selama ada perbedaan harga. Oleh karena itu, spread harga lindung nilai juga memiliki nilai pemicu. Jika lebih rendah dari spread harga tertentu, lindung nilai akan membuat kerugian.

Berdasarkan hal itu, strategi harus dirancang dengan beberapa parameter:

  • Spread lindung nilai:hedgeDiffPrice; ketika spread melebihi nilai, lindung nilai akan dipicu.
  • Jumlah minimum lindung nilai:minHedgeAmount, jumlah pesanan minimum (jumlah simbol) yang tersedia untuk lindung nilai.
  • Jumlah maksimum lindung nilai:maxHedgeAmount, jumlah pesanan maksimum (jumlah simbol) yang tersedia untuk lindung nilai.
  • Keakuratan harga A:pricePrecisionA, presisi harga order (angka desimal) dari platform A.
  • Keakuratan jumlah pesanan A:amountPrecisionA, presisi jumlah pesanan (angka desimal) dari platform A.
  • Keakuratan harga B:pricePrecisionB, presisi harga order (angka desimal) dari platform B.
  • Keakuratan jumlah pesanan B:amountPrecisionB, presisi jumlah pesanan (angka desimal) dari platform B.
  • Nilai tukar A:rateA, nilai tukar yang dikonversi dari objek pertukaran pertama yang ditambahkan; default adalah 1, yang menunjukkan tidak akan dikonversi.
  • Nilai tukar B:rateB, nilai tukar yang dikonversi dari objek pertukaran kedua yang ditambahkan; default adalah 1, yang menunjukkan tidak akan dikonversi.

Strategi lindung nilai perlu menjaga jumlah simbol mata uang dari kedua akun tidak berubah (yaitu, tidak memegang posisi arah, dan menjaga netral), sehingga perlu ada logika keseimbangan dalam strategi untuk selalu mendeteksi saldo.

  • 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 order, jika tidak ada order yang dieksekusi, kita perlu membatalkannya tepat waktu, dan order tidak dapat tetap menunggu. operasi ini perlu diproses baik dalam modul saldo dan logika lindung nilai, jadi juga perlu untuk merancang fungsi membatalkan semua order.

  • 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 simbol mata uang, kita perlu menemukan harga dengan jumlah tertentu dalam data kedalaman tertentu, jadi kita perlu fungsi seperti ini 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 secara bersamaan menempatkan pesanan:

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

Fungsi-fungsi ini telah dirancang sesuai dengan persyaratan strategi, dan kita dapat mulai merancang fungsi utama strategi.

Strategi Desain Fungsi Utama

Di FMZ, strategi dilaksanakan darimainPada awalmainfungsi, kita perlu melakukan beberapa inisialisasi strategi.

  • Nama Obyek Exchange Untuk banyak operasi dalam strategi menggunakan objek pertukaran, seperti mendapatkan penawaran pasar, menempatkan pesanan, dan sebagainya, Jadi akan tidak nyaman untuk menggunakan nama yang lebih panjang setiap kali, trik kecil saya adalah untuk menggunakan nama pendek sederhana sebagai gantinya, misalnya:

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

    Kemudian, akan lebih nyaman untuk menulis kode nanti.

  • Nilai tukar & Keakuratan

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

    Jika salah satu parameter nilai tukar, yaiturateAdanrateB, ditetapkan menjadi 1 (default adalah 1), yaitu,rateA != 1ataurateB != 1berarti tidak dipicu, dan nilai tukar tidak dapat dikonversi.

  • Setel kembali semua tanggal

    img

    Kadang-kadang, perlu untuk menghapus semua log dan vakum catatan data ketika strategi dimulai.isReset, dan kemudian 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")
      }
    
  • Pulihkan Data Akun Awal dan Perbarui Data Akun Saat Ini Untuk menilai saldo, strategi perlu terus mencatat kondisi aset rekening awal untuk perbandingan dengan yang saat ini.nowAccsdigunakan untuk mencatat data rekening arus.updateAccsfungsi yang baru saja kami rancang untuk mendapatkan data akun dari platform saat ini.initAccsdigunakan untuk mencatat status akun awal (data seperti jumlah simbol mata uang dari kedua A dan B, jumlah mata uang kutipan, dll.).initAccs, pertama-tama gunakan_G()fungsi untuk mengembalikan (fungsi _G akan mencatat data secara terus menerus, dan dapat mengembalikan data yang tercatat lagi; baca dokumentasi API untuk rincian:link).
    Jika Anda tidak dapat menanyakan data, gunakan informasi rekening current untuk menetapkan dan menggunakan_G()fungsi untuk merekam.

    Seperti kode berikut:

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

Logika Trading, Main Loop dalam Fungsi Utama

Kode dalam loop utama adalah proses dari setiap putaran eksekusi logika strategi, dan eksekusi berulang tanpa henti membangun strategi loop utama.

  • Dapatkan Kutipan Pasar dan Hukum Validitasnya

          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 Anda dapat melihat bahwa fungsi paralelexchange.Godari platform FMZ digunakan untuk membuat objek bersamaandepthARoutinedandepthBRoutineyang disebutGetDepth()Ketika dua objek bersamaan ini dibuat,GetDepth()interface dipanggil segera, dan kedua permintaan untuk data kedalaman dikirim ke platform. Lalu, hubungiwait()metode objekdepthARoutinedan objekdepthBRoutineuntuk mendapatkan data kedalaman. Setelah mendapatkan data kedalaman, perlu untuk memeriksa data kedalaman untuk menilai keabsahannya.continuepernyataan dipicu untuk mengeksekusi kembali loop utama.

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

    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

    ParameterdiffAsPercentagetelah ditambahkan ke parameter antarmuka strategi. dua parameter lainnya, yang akan menunjukkan atau menyembunyikan berdasarkan parameter ditetapkan sebagai:hedgeDiffPrice@!diffAsPercentage; ketikadiffAsPercentageadalah palsu, itu akan ditunjukkan.hedgeDiffPercentage@diffAsPercentage; ketikadiffAsPercentageadalah benar, itu akan ditampilkan.
    Setelah desain, kami telah memeriksadiffAsPercentageparameter, yaitu menggunakan rasio spread sebagai kondisi pemicu lindung nilai.diffAsPercentageparameter tidak diperiksa, spread harga digunakan sebagai kondisi pemicu lindung nilai.

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

    Ada beberapa kondisi pemicu untuk lindung nilai: 1.Pertama, memenuhi spread lindung nilai; hanya ketika spread pasar memenuhi parameter spread yang ditetapkan, lindung nilai dapat dimungkinkan.

    2.Jumlah lindung nilai pasar harus memenuhi jumlah lindung nilai minimum yang ditetapkan dalam parameter.Karena jumlah pesanan minimum dari platform yang berbeda, yang terkecil dari keduanya harus diambil.

    3.Aset di platform dengan operasi jual cukup untuk menjual, dan aset di platform dengan operasi pembelian cukup untuk membeli. Ketika kondisi ini terpenuhi, eksekusi fungsi lindung nilai untuk menempatkan pesanan dengan lindung nilai. Sebelum fungsi utama, kita menyatakan variabelisTradeDi sini, jika lindung nilai dipicu, variabel diatur untuktrueDan reset variabel globallastKeepBalanceTSke 0 (lastKeepBalanceTS digunakan untuk menandai timestamp dari operasi saldo terakhir, dan mengaturnya ke 0 akan memicu operasi saldo segera), dan kemudian membatalkan semua pesanan yang menunggu.

  • Operasi Saldo

          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 jikalastKeepBalanceTSSetelah operasi lindung nilai ditetapkan kembali ke 0 setelah operasi lindung nilai dipicu, operasi saldo akan dipicu segera.

  • Informasi 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", 
              "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)
    

    Bar status tidak dirancang untuk menjadi sangat rumit. Ini menampilkan waktu saat ini, spread harga dari platform A ke platform B serta spread harga dari B ke A; juga menampilkan spread target lindung nilai saat ini, data aset akun platform A, dan data aset akun platform B.

Pengolahan Pasangan Perdagangan untuk Mata Uang Kuotasi yang Berbeda

Dalam hal parameter, kami merancang parameter konversi nilai nilai nilai tukar, dan kami juga telah merancang konversi nilai tukar dalam operasi awal darimainHal ini harus dicatat bahwaSetRateFungsi konversi nilai tukar harus dijalankan terlebih dahulu.

Untuk fungsi akan mempengaruhi dua aspek:

  • Konversi harga dalam semua data penawaran pasar, data pesanan, dan data posisi.
  • Konversi mata uang kutipan menjadi aset rekening.

Misalnya, pasangan perdagangan saat ini adalahBTC_USDT, satuan harga adalahUSDT, dan mata uang penawaran yang tersedia dalam aset rekening jugaUSDTJika saya ingin mengkonversi nilai aset ke CNY, aturexchange.SetRate(6.8)dalam kode untuk mengubah data yang diperoleh oleh semua fungsi di bawahexchangeobjek, dan kemudian mengubahnya menjadi CNY. Untuk mengkonversi ke mata uang penawaran, impornilai tukar dari mata uang penawaran saat ini ke mata uang penawaran targetke dalamSetRate function.

Strategi lengkap:Strategi Hedge Spot dari Mata Uang Kuotasi yang Berbeda (Teaching)


Lebih banyak