Cryptocurrency Spot Hedge Strategy (2)

Author: Ninabadass, Created: 2022-04-14 16:17:46, Updated: 2022-04-15 14:16:23

Cryptocurrency Spot Hedge Strategy (2)

In the previous article, we implemented a simple hedge strategy together, and then we will learn how to upgrade the strategy. There are not many modifications in the strategy, but the details of the modifications need attention. The definitions of some places in the code have been modified, compared with the previous ones, which need to be understood specifically.

Requirements for Upgrading the Strategy

  • Switch spot exchange object margin mode The modification is only related to the bot. Some spot platforms have spot margin interfaces, which are also encapsulated on FMZ. For the exchange objects that are directly encapsulated on FMZ and support spot margin, you can directly switch the mode.
  • Add more spread chart display For adding more spread chart display, and we only plot the spread curves of A->B and B->A, as well as the horizontal spread trigger lines, we can directly use the chart plot library; the advantage is the simpleness and easy use. From here, we also learn how to use the function of FMZ template library together.
  • Function of single sided hedge This modification is relatively big, because it is difficult to completely reverse the price spread between the two platforms during the specific hedge trading. Most of the time, the price on one platform is consistently higher than the price on another platform. At this time, if our assets have been fully hedged (that is, all the currency symbols are in the platform with the lower prices, and the assets are all in the platform with the higher prices). The hedge is stagnant, and it is no longer possible to depend on the spread volatility to make a profit. At this time, you need to make the strategy to hedge and return the currency symbols back by only losing little amount of assets (let the currency symbols back to the platform with the higher prices again). When the price spread becomes larger again, you can continue to hedge and make profits.
  • Interactively modify parameters like hedge spread line
    Add the interactive function to the strategy, so as to modify the spread trigger line in real time.
  • Manage the status bar information and display it in the table format Arrange and manage the data that need to be displayed, for convenient observation.

Next, let’s realize those designing ideas one by one.

Switch spot exchange object margin mode

Take Binance spot bot as an example. To switch to spot margin mode, use the code exchanges[i].IO, import the parameter trade_normal to switch to isolated margin, and import trade_super_margin to switched to cross margin, which is not supported in backtest. That can only be used in bots.

In the preparation at the beginning of the main function, add:

    // switch the margin mode 
    for (var i = 0 ; i < exchanges.length ; i++) {   // traverse and detect all exchange objects added
        if (exchanges[i].GetName() == "Binance" && marginType != 0) {   // if the exchange object represented by the current index i is Binance Spot, and the parameter marginType on the strategy interface is not selected as the "common spot" option, execute the switch
            if (marginType == 1) {
                Log(exchanges[i].GetName(), "set to isolated margin")
                exchanges[i].IO("trade_normal")
            } else if (marginType == 2) {
                Log(exchanges[i].GetName(), "set to cross margin")
                exchanges[i].IO("trade_super_margin")
            }
        }
    }

The strategy here only adds the code for switching the spot margin mode of Binance Spot, so the switch setting in the strategy parameters only works for Binance Spot.

Add more spread chart display

Using the encapsulated plotting templates is very simple. The template name we use here is chart plot Library. You can directly search for it in the Square of FMZ platform .

img

Or you can directly click the link: https://www.fmz.com/strategy/27293 to skip to the copy page of the template.

img

Click the button and you can easily copy the template to your own strategy library.

img

Then, on the strategy editing page, you can check the template library to be used in the template column. Save the strategy after checking it, and the strategy will use this template. This is just a brief description of the use of the template library. Since the strategy has already referenced this template, there is no need to repeat the operation. When you copy the strategy code in Square, you can see that chart plot Library has been referenced in the template bar of the strategy editing page.

Here we mainly learn how to use the functions of the chart plot library to plot.

img

We plan to plot the spreads of A->B and B->A, and the trigger line of the spread. We need to plot two curves (currently, the spreads of A to B and B to A), and two horizontal lines (spread trigger lines), as shown in the figure above.

Because we want to design a single sided hedge, the trigger lines of A->B and B->A will be different, and we can not use the design in the previous article. In the previous article:

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

There is only one triggered spread targetDiffPrice. Therefore, here we need to modify the code, and we need to modify the parameters first.

img

then, modify the code:

        var targetDiffPriceA2B = hedgeDiffPriceA2B
        var targetDiffPriceB2A = hedgeDiffPriceB2A
        if (diffAsPercentage) {
            targetDiffPriceA2B = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageA2B
            targetDiffPriceB2A = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentageB2A
        }

Thus, the spread trigger line has changed from the previous one targetDiffPrice to two, namely targetDiffPriceA2B and targetDiffPriceB2A. Next, you can use the chart plotting function of the chart plot library to draw the data on the chart.

        // plot
        $.PlotHLine(targetDiffPriceA2B, "A->B")  // the first parameter of the function is the value of the horizontal line in the Y-axis direction, and the second parameter is the display text
        $.PlotHLine(targetDiffPriceB2A, "B->A")

When the strategy is run, the chart will be displayed like this.

img

Next, draw the real-time spread curve; in order to avoid over drawing, put the code that plots the real-time spread curves in the balance detection. s

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

            $.PlotLine("A2B", depthA.Bids[0].Price - depthB.Asks[0].Price)  // plot real-time spread curves
            $.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price)  // the first parameter is the curve name, and the second parameter is the curve value at the current moment, that is, the value in the Y-axis direction at the current moment
        }

The plotting code only needs 4 lines to allow the strategy with a chart display during runing.

Function of Single Sided Hedge

As mentioned above, the number of the spread trigger line has been changed into two, which respectively control the hedge trigger of A->B and B->A. In this way, the previous order price algorithm cannot be used, and the method of adding slide price to the market price is used instead.

        if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPriceA2B && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) {          // A->B market condition satisfied             
            var priceSell = depthA.Bids[0].Price - slidePrice
            var priceBuy = depthB.Asks[0].Price + slidePrice
            var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
            if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance * 0.8 / priceSell > minHedgeAmount) {
                amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance * 0.8 / priceSell, maxHedgeAmount)
                Log("triggerA->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks)  // prompt message
                hedge(exB, exA, priceBuy, priceSell, amount)
                cancelAll()
                lastKeepBalanceTS = 0
                isTrade = true 
            }            
        } else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPriceB2A && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) {   // B->A market condition satisfied 
            var priceBuy = depthA.Asks[0].Price + slidePrice
            var priceSell = depthB.Bids[0].Price - slidePrice
            var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
            if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance * 0.8 / priceBuy > minHedgeAmount) {
                amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance * 0.8 / priceBuy, maxHedgeAmount)
                Log("triggerB->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks)  // prompt message
                hedge(exA, exB, priceBuy, priceSell, amount)
                cancelAll()
                lastKeepBalanceTS = 0
                isTrade = true 
            }            
        }

Since buy and sell prices are split into two pieces of data, the hedge function also needs to be modified.

function hedge(buyEx, sellEx, priceBuy, priceSell, amount) {
    var buyRoutine = buyEx.Go("Buy", priceBuy, amount)
    var sellRoutine = sellEx.Go("Sell", priceSell, amount)
    Sleep(500)
    buyRoutine.wait()
    sellRoutine.wait()
}

There are also some minor adjustments based on these modifications, which will not be described here. You can look at the code for details.

Interactively modify parameters like hedge spread line

Add interaction to the strategy, so that the strategy can modify the spread trigger line in real time. That is also the design requirement of a semi-automatic strategy, which will also be implemented here as a teaching demo. The strategy interaction design is also very simple. First, add interactive controls to the strategy on the strategy editing page.

img

There were two controls added, one called A2B and the other one called B2A. After entering a value in the control input box, click the button on the right of the input box. A command will be sent to the strategy immediately, for example: enter the value 123 in the input box, click the A2B button, and a command will be sent to the strategy immediately.

A2B:123

Design interactive detection and processing code in the strategy code.

        // interaction 
        var cmd = GetCommand()   // every time when the loop is operated here, it will detect whether an interactive command is sent; if no, return null string 
        if (cmd) {               // interactive command detected, such as A2B:123
            Log("received command:", cmd)
            var arr = cmd.split(":")   // split out the interactive control name and the value in the input box; arr[0] means A2B, and arr[1] means 123
            if (arr[0] == "A2B") {     // judge whether the triggered interactive control is A2B
                Log("modify parameterA2B,", diffAsPercentage ? "parameter of spread ratio:" : "parameter of spread:", arr[1])
                if (diffAsPercentage) {
                    hedgeDiffPercentageB2A = parseFloat(arr[1])     // modify the spread trigger line 
                } else {
                    hedgeDiffPriceA2B = parseFloat(arr[1])          // modify the spread trigger line 
                }
            } else if (arr[0] == "B2A") {           // detected the triggered control is B2A 
                Log("modify parameterB2A,", diffAsPercentage ? "parameter of spread ratio:" : "parameter of spread:", arr[1])
                if (diffAsPercentage) {
                    hedgeDiffPercentageA2B = parseFloat(arr[1])
                } else {
                    hedgeDiffPriceB2A = parseFloat(arr[1])
                }
            }
        }

Manage the status bar information and display it in the table format

Make the status bar data display more regulated and easy to observe.

        var tbl = {
            "type" : "table", 
            "title" : "data", 
            "cols" : ["platform", "Currency", "frozenCurrrency", "quoteCurrency", "frozenQuoteCurrency", "triggerSpread", "currentSpread"], 
            "rows" : [], 
        }
        tbl.rows.push(["A:" + exA.GetName(), nowAccs[0].Stocks, nowAccs[0].FrozenStocks, nowAccs[0].Balance, nowAccs[0].FrozenBalance, "A->B:" + targetDiffPriceA2B, "A->B:" + (depthA.Bids[0].Price - depthB.Asks[0].Price)])
        tbl.rows.push(["B:" + exB.GetName(), nowAccs[1].Stocks, nowAccs[1].FrozenStocks, nowAccs[1].Balance, nowAccs[1].FrozenBalance, "B->A:" + targetDiffPriceB2A, "B->A:" + (depthB.Bids[0].Price - depthA.Asks[0].Price)])

        LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")

img

Backtest

The backtest is only a test of the strategy, as a preliminary detection function. Many bugs can actually be tested in the backtest stage. It is not necessary to care too much about the backtest results. Eventually, the strategy still needs to be tested in the actual environment with real bots.

img

img

Strategy source code: https://www.fmz.com/strategy/302834


More