Strategi Hedge Spot Cryptocurrency (1)

Penulis:Ninabadass, Dicipta: 2022-04-14 11:57:46, Dikemas kini: 2022-04-14 16:32:56

Strategi Hedge Spot Cryptocurrency (1)

Untuk pemula dalam reka bentuk strategi, strategi lindung nilai adalah satu yang sangat baik untuk amalan.

Fungsi Reka Bentuk & Parameter mengikut Keperluan Strategi

Pertama sekali, kita perlu memastikan bahawa strategi yang akan direka adalah strategi lindung nilai mata wang kripto spot. Kami merancang lindung nilai yang paling mudah. Kami hanya menjual di platform dengan harga yang lebih tinggi di antara dua platform spot, dan membeli di platform dengan harga yang lebih rendah untuk memperoleh spread harga. Apabila platform dengan harga yang lebih tinggi penuh dengan simbol mata wang kutipan (kerana harga tinggi, semua simbol mata wang dijual), atau apabila platform dengan harga yang lebih rendah penuh dengan simbol mata wang (kerana harga rendah, simbol mata wang dibeli oleh semua aset), ia tidak dapat dilindung nilai. Pada masa ini, anda hanya boleh menunggu harga terbalik untuk lindung nilai.

Untuk harga pesanan dan jumlah semasa lindung nilai, terdapat had ketepatan di setiap platform, dan juga terdapat had pada jumlah pesanan minimum. Selain had minimum, strategi juga perlu mempertimbangkan jumlah pesanan maksimum untuk lindung nilai. Jika jumlah pesanan terlalu besar, pasaran tidak akan mempunyai jumlah pesanan yang mencukupi untuk itu. Ia juga perlu mempertimbangkan bagaimana menukar kadar pertukaran jika kedua-dua platform mempunyai mata wang kutipan yang berbeza. Yuran penanganan semasa lindung nilai dan slippage pemegang pesanan adalah semua kos perdagangan. lindung nilai tidak selalu berlaku selagi terdapat perbezaan harga. Oleh itu, penyebaran harga lindung nilai juga mempunyai nilai pemicu. Jika lebih rendah daripada penyebaran harga tertentu, lindung nilai akan membuat kerugian.

Berdasarkan itu, strategi perlu direka dengan beberapa parameter:

  • Spread lindung nilai:hedgeDiffPrice; apabila perbezaan melebihi nilai, lindung nilai akan dicetuskan.
  • Jumlah lindung nilai minimum:minHedgeAmount, jumlah pesanan minimum (jumlah simbol) yang tersedia untuk lindung nilai.
  • Jumlah lindung nilai maksimum:maxHedgeAmount, jumlah pesanan maksimum (jumlah simbol) yang tersedia untuk lindung nilai.
  • Ketepatan harga A:pricePrecisionA, ketepatan harga pesanan (angka perpuluhan) platform A.
  • Kecekapan jumlah pesanan A:amountPrecisionA, ketepatan jumlah pesanan (angka perpuluhan) platform A.
  • Ketepatan harga B:pricePrecisionB, ketepatan harga pesanan (angka perpuluhan) platform B.
  • Kecekapan jumlah pesanan B:amountPrecisionB, ketepatan jumlah pesanan (angka perpuluhan) platform B.
  • Kadar pertukaran A:rateA, kadar pertukaran menukar objek pertukaran pertama yang ditambah; lalai adalah 1, yang menunjukkan tidak untuk menukar.
  • Kadar pertukaran B:rateB, kadar pertukaran menukar objek pertukaran kedua yang ditambah; lalai adalah 1, menunjukkan tidak untuk menukar.

Strategi lindung nilai perlu mengekalkan jumlah simbol mata wang dari kedua-dua akaun tidak berubah (iaitu, tidak memegang mana-mana kedudukan arah, dan mengekalkan neutral), jadi perlu ada logik baki 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 dilaksanakan, kita perlu membatalkannya tepat pada masanya, dan pesanan tidak boleh disimpan menunggu. Operasi ini perlu diproses di kedua-dua modul baki dan logik lindung nilai, jadi ia juga perlu untuk merancang fungsi membatalkan semua pesanan.

  • 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 simbol mata wang, kita perlu mencari harga dengan jumlah tertentu dalam data kedalaman tertentu, jadi kita memerlukan fungsi seperti ini 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 sedikit lebih 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 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 direka mengikut keperluan strategi, dan kita boleh mula merancang fungsi utama strategi.

Strategi Reka Bentuk Fungsi Utama

Pada FMZ, strategi dilaksanakan darimainPada permulaanmainfungsi, kita perlu melakukan beberapa inisialisasi strategi.

  • Nama Objek Exchange Untuk banyak operasi dalam strategi menggunakan objek pertukaran, seperti mendapatkan sebut harga pasaran, meletakkan pesanan, dan sebagainya, jadi ia akan menjadi tidak selesa untuk menggunakan nama yang lebih lama setiap kali, trik kecil saya adalah untuk menggunakan nama pendek yang mudah sebagai gantinya, sebagai contoh:

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

    Kemudian, ia akan lebih selesa untuk menulis kod kemudian.

  • Kadar Pertukaran & Ketepatan

      // 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 kadar pertukaran, iaiturateAdanrateB, ditetapkan kepada 1 (default adalah 1), iaitu,rateA != 1ataurateB != 1bermakna tidak dicetuskan, dan kadar pertukaran tidak boleh ditukar.

  • Tetapkan semula semua tarikh

    img

    Kadang-kadang, ia adalah perlu untuk memadamkan semua log dan vakum rekod data apabila strategi dimulakan.isReset, dan kemudian 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 Awal dan Mengemas kini Data Akaun semasa Untuk menilai baki, strategi perlu terus mencatat keadaan aset akaun awal untuk perbandingan dengan yang semasa.nowAccsdigunakan untuk merakam data akaun semasa.updateAccsFungsi yang kita buat untuk mendapatkan data akaun platform semasa.initAccsdigunakan untuk merakam status akaun awal (data seperti jumlah simbol mata wang kedua-dua A dan B, jumlah mata wang sebut harga, dll.).initAccs, mula-mula gunakan_G()fungsi untuk memulihkan (fungsi _G akan merakam data secara berterusan, dan boleh mengembalikan data yang direkodkan lagi; baca dokumentasi API untuk butiran:pautan).
    Jika anda tidak boleh pertanyaan data, menggunakan maklumat akaun semasa untuk menetapkan dan menggunakan_G()fungsi untuk merekod.

    Seperti kod berikut:

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

Logik Perdagangan, Loop Utama dalam Fungsi Utama

Kod dalam gelung utama adalah proses setiap pusingan pelaksanaan logik strategi, dan pelaksanaan berulang tanpa henti membina gelung utama strategi.

  • Dapatkan Kutipan Pasaran dan Menilai Validiti

          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 boleh melihat bahawa fungsi serentakexchange.Godari platform FMZ digunakan untuk mencipta objek serentakdepthARoutinedandepthBRoutineyang memanggilGetDepth()Apabila kedua-dua objek serentak ini dicipta,GetDepth()Antara muka dipanggil dengan segera, dan kedua-dua permintaan untuk data kedalaman dihantar ke platform. Kemudian, hubungiwait()kaedah objekdepthARoutinedan objekdepthBRoutineuntuk mendapatkan data kedalaman. Selepas mendapatkan data kedalaman, adalah perlu untuk memeriksa data kedalaman untuk menilai kesahihannya.continuePerintah akan dicetuskan untuk menjalankan semula gelung 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
          }
    

    Dari segi parameter, kita 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. dua parameter lain, yang akan menunjukkan atau menyembunyikan berdasarkan parameter ditetapkan sebagai:hedgeDiffPrice@!diffAsPercentage; apabiladiffAsPercentageadalah palsu, ia akan ditunjukkan.hedgeDiffPercentage@diffAsPercentage; apabiladiffAsPercentageadalah benar, ia akan ditunjukkan.
    Selepas reka bentuk, kami telah memeriksadiffAsPercentageparameter, yang adalah untuk menggunakan nisbah spread sebagai keadaan pencetus lindung nilai.diffAsPercentageparameter tidak diperiksa, spread harga digunakan sebagai keadaan pencetus 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 
              }            
          }
    

    Terdapat beberapa syarat pemicu untuk lindung nilai: 1.Pertama, memenuhi spread lindung nilai; hanya apabila spread pasaran memenuhi parameter spread yang ditetapkan, lindung nilai boleh dilakukan.

    2.Jumlah lindung nilai pasaran harus memenuhi jumlah lindung nilai minimum yang ditetapkan dalam parameter.

    3.Aset dalam platform dengan operasi jualan adalah cukup untuk menjual, dan aset dalam platform dengan operasi pembelian adalah cukup untuk membeli. Apabila syarat-syarat ini dipenuhi, melaksanakan fungsi lindung nilai untuk meletakkan pesanan dengan lindung nilai. Sebelum fungsi utama, kita mengisytiharkan pembolehubahisTradedi hadapan untuk menandakan sama ada lindung nilai berlaku. di sini, jika lindung nilai dicetuskan, pembolehubah ditetapkan kepadatrue. Dan menetapkan semula pembolehubah globallastKeepBalanceTSkepada 0 (lastKeepBalanceTS digunakan untuk menandakan cap masa operasi baki terakhir, dan menetapkannya kepada 0 akan mencetuskan operasi baki dengan serta-merta), dan kemudian membatalkan semua pesanan yang menunggu.

  • Operasi imbangan

          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 imbangan 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", 
              "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 direka untuk menjadi sangat rumit. Ia memaparkan masa semasa, harga penyebaran dari platform A ke platform B serta harga penyebaran dari B ke A; ia juga memaparkan penyebaran sasaran lindung nilai semasa, data aset akaun platform A, dan data aset akaun platform B.

Pemprosesan Pasangan Dagangan untuk Mata Wang Petikan Berbeza

Dari segi parameter, kita telah merancang parameter menukar nilai kadar pertukaran, dan kita juga telah merancang penukaran kadar pertukaran dalam operasi awal sistem.mainIa harus diperhatikan bahawaSetRateFungsi penukaran kadar pertukaran perlu dilaksanakan terlebih dahulu.

Untuk fungsi akan mempengaruhi dua aspek:

  • Penukaran harga dalam semua data sebut harga pasaran, data pesanan, dan data kedudukan.
  • Penukaran mata wang sebut harga kepada aset akaun.

Sebagai contoh, pasangan dagangan semasa adalahBTC_USDT, unit harga adalahUSDT, dan mata wang sebut harga yang tersedia dalam aset akaun jugaUSDTJika saya mahu menukar nilai aset ke CNY, tetapkanexchange.SetRate(6.8)dalam kod untuk menukar data yang diperoleh oleh semua fungsi di bawahexchangeobjek, dan kemudian menukar kepada CNY. Untuk menukar kepada apa mata wang sebut harga, importkadar pertukaran dari mata wang sebut harga semasa ke mata wang sebut harga sasaranke dalamSetRate function.

Strategi lengkap:Strategi lindung nilai spot mata wang sebut harga yang berbeza (Pengajaran)


Lebih lanjut