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.
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.Let's implement these designs one by one.
Using real currency as an example, switching to the real currency leverage mode using codeexchanges[i].IO
, input parameterstrade_normal
Switching to leverage, passing intrade_super_margin
Switching to full leverage, retesting not supported. This is only used when the lever is in the live position.
In themain
The 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.
It's very simple to use a picture template that's already packaged.画线类库
│ can be searched directly on FMZ's Strategy Square.
You can also click on the link below:https://www.fmz.com/strategy/27293Jump to copy page of this template.
Click the button to copy this template library to your policy library.
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.
We're planning toA->B
The price difference between the two countries is very high.B->A
Draw 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->B
andB->A
The 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 differencetargetDiffPrice
I'm not going to lie.
So here we're going to rewrite the code, first we're going to rewrite the parameters.
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.targetDiffPrice
One becomes two.targetDiffPriceA2B
、targetDiffPriceB2A
I'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.
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.
The above article mentions that the difference trigger line has been transformed into two lines, each controlled by a different controller.A->B
This is the first time that the country has seen such a trend.B->A
This 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.hedge
I'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.
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.
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.123
Click hereA2B
This 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])
}
}
}
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) + "`")
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.
The source code of the strategy:https://www.fmz.com/strategy/302834
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
Inventors quantify - small dreamsI'm glad I had the opportunity to teach you a lesson.
Light cloudsI understand, thank you very much.
Inventors quantify - small dreamsAdd two exchange objects.