Design of a cash hedging strategy for digital currency (2)

Author: The Little Dream, Created: 2021-07-30 16:36:48, Updated: 2023-09-20 10:36:43

img

Design of a cash hedging strategy for digital currency (2)

In the previous article, we implemented a simple hedging strategy together, and then we learn how to upgrade this strategy. The policy changes will not be large, but the details of the changes will need to be taken into account. Definitions in some places of the code and previous changes need to be understood.

The need to upgrade this strategy

  • Switching the leverage mode of the spot exchange This change only applies to physical disks, and some spot trades have all the spot leverage interfaces, which are also wrapped on FMZ. Direct switching mode is available for exchange objects that are directly wrapped on FMZ and support spot leverage.
  • Increased price differential chart The increase in the difference graph is shown because it's just drawing.A交易所->B交易所B交易所->A交易所We're going to draw the horizontal line that triggers the difference.画线类库The advantage is that it's simple and easy to use, and here we're learning how to use FMZ.模版类库It's a feature.
  • Unilateral hedging This change can be said to be relatively large, because it is difficult to completely reverse the difference between the two exchanges in a specific hedging transaction. Most of the time, the price of one exchange remains higher than the price of the other exchange. At this time, if our assets have been fully hedged (i.e. all the coins are on the low-priced exchange, all the money is on the high-priced exchange).
  • Parameters such as Interactive Modified Hedge Spread Added interactive functionality to the policy, allowing you to modify the price differential trigger line in real time.
  • Organize the status bar information to display it in a form The data that needs to be displayed is organized so that it is easy to observe.

Let's implement these designs one by one.

Switching the leverage mode of the spot exchange

Using real currency as an example, switching to the real currency leverage mode using codeexchanges[i].IO, input parameterstrade_normalSwitching to leverage, passing intrade_super_marginSwitching to full leverage, retesting not supported. This is only used when the lever is in the live position.

In themainThe preparation phase for the start of the function increases:

    // 切换杠杆模式
    for (var i = 0 ; i < exchanges.length ; i++) {   // 遍历检测所有添加的交易所对象
        if (exchanges[i].GetName() == "Binance" && marginType != 0) {   // 如果当前i索引代表的交易所对象是币安现货,并且策略界面参数marginType选择的不是「普通币币」选项,执行切换
            if (marginType == 1) {
                Log(exchanges[i].GetName(), "设置为杠杆逐仓")
                exchanges[i].IO("trade_normal")
            } else if (marginType == 2) {
                Log(exchanges[i].GetName(), "设置为杠杆全仓")
                exchanges[i].IO("trade_super_margin")
            }
        }
    }

The only code added to the policy is the currency leverage mode for switching to fiat cash, so setting the switch to the policy parameter is only valid for fiat cash.

Increased price differential chart

It's very simple to use a picture template that's already packaged.画线类库│ can be searched directly on FMZ's Strategy Square.

img

You can also click on the link below:https://www.fmz.com/strategy/27293Jump to copy page of this template.

img

Click the button to copy this template library to your policy library.

img

Then, on the policy edit page, you can select the template library you need in the template window. Select Save Policy and the policy will reference this template. This is just a brief description of the template library, which has already been referenced in this template so you do not have to repeat the operation.画线类库I've been quoted in the past.

We're mainly learning how to use it.画线类库This is a function that draws a graph.

img

We're planning toA->BThe price difference between the two countries is very high.B->ADraw two curves (current A to B and B to A) and two horizontal lines (triggered price line), as shown above.

We're going to design a one-sided hedge.A->BandB->AThe design of the trigger line is not the same. 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
      }

Only one triggered the differencetargetDiffPriceI'm not going to lie. So here we're going to rewrite the code, first we're going to rewrite the parameters.

img

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

The price differential is triggered by the price difference between the two currencies.targetDiffPriceOne becomes two.targetDiffPriceA2BtargetDiffPriceB2AI'm not sure. The next thing you can do is to use the drawing line function in the drawing line library to draw this data on the graph.

        // 画图
        $.PlotHLine(targetDiffPriceA2B, "A->B")  // 该函数第一个参数是水平线在Y轴方向上的值,第二个参数是显示文本
        $.PlotHLine(targetDiffPriceB2A, "B->A")

This is a graph showing how the strategy works.

img

Next, draw a real-time differential curve to avoid excessive drawing lines. Place the code of the real-time differential data drawing curve in the balance check.

        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)  // 画实时差价曲线
            $.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price)  // 第一个参数是曲线名称,第二个参数是曲线当前时刻的值,即当前时刻Y轴方向上的值
        }

This allows a chart to be displayed when the policy is running, with only four lines of code.

One-sided hedging

The above article mentions that the difference trigger line has been transformed into two lines, each controlled by a different controller.A->BThis is the first time that the country has seen such a trend.B->AThis is the first time that a hedge has been triggered. This prevents the use of the previous down-order price algorithm and replaces it with a discounted price.

        if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPriceA2B && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) {          // A -> B 盘口条件满足            
            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("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks)  // 提示信息
                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 盘口条件满足
            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("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks)  // 提示信息
                hedge(exA, exB, priceBuy, priceSell, amount)
                cancelAll()
                lastKeepBalanceTS = 0
                isTrade = true 
            }            
        }

And since the buy and sell price is separated into two data points, the hedge function is going to be the same.hedgeI'm not sure what you mean by that.

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 changes, which are not described here, but can be seen specifically in the code.

Parameters such as interactive modified hedge spread

Adding interaction to the strategy to allow the strategy to modify the differential trigger line in real time. This is a design requirement for a semi-automated strategy, which is also implemented here as a teaching demonstration. Policy interaction design is also very simple, first adding interaction controls to the policy on the policy edit page.

img

Two controls are added, one called A2B and one called B2A. After entering a value in the control's input box, click the input button on the right side. It immediately sends a command to the policy, for example: enter a number in the input box.123Click hereA2BThis button immediately sends instructions to the policy.

A2B:123

Interaction detection and processing of code in the design of strategy code.

        // 交互
        var cmd = GetCommand()   // 每次循环执行到这里时,都检测有没有交互指令过来,没有则返回空字符串
        if (cmd) {               // 检测到有交互指令,例如:A2B:123
            Log("接收到命令:", cmd)
            var arr = cmd.split(":")   // 拆分出交互控件名称和输入框中的值,arr[0]就是A2B,arr[1]就是123
            if (arr[0] == "A2B") {     // 判断触发的交互控件是不是A2B
                Log("修改A2B的参数,", diffAsPercentage ? "参数为差价百分比" : "参数为差价:", arr[1])
                if (diffAsPercentage) {
                    hedgeDiffPercentageB2A = parseFloat(arr[1])     // 修改触发差价线
                } else {
                    hedgeDiffPriceA2B = parseFloat(arr[1])          // 修改触发差价线
                }
            } else if (arr[0] == "B2A") {           // 检测到触发的控件是B2A     
                Log("修改B2A的参数,", diffAsPercentage ? "参数为差价百分比" : "参数为差价:", arr[1])
                if (diffAsPercentage) {
                    hedgeDiffPercentageA2B = parseFloat(arr[1])
                } else {
                    hedgeDiffPriceB2A = parseFloat(arr[1])
                }
            }
        }

Organize the status bar information to display it in a form

This makes the status bar data more orderly and easy to observe.

        var tbl = {
            "type" : "table", 
            "title" : "数据", 
            "cols" : ["交易所", "币", "冻结币", "计价币", "冻结计价币", "触发差价", "当前差价"], 
            "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

Reassessment

Re-testing is only a test strategy, a preliminary detection function, many bugs can actually be tested at the re-test stage. It is not necessary to care too much about the re-test results, the final strategy still requires real-gun live bullets to be detected in a real environment.

img

img

The source code of the strategy:https://www.fmz.com/strategy/302834


Related

More

15570686905So this trading strategy, adding contract functionality, it's just good to add permanent contracts, all of these contracts, all of these contracts.

Light cloudsTypeError: Cannot read property 'SetPrecision' of undefined Hedging strategies for different currencies Ver 1.1

The Little DreamI'm glad I had the opportunity to teach you a lesson.

Light cloudsI understand, thank you very much.

The Little DreamAdd two exchange objects.