
이전 글에서 우리는 간단한 헤지 전략을 구현했습니다. 다음으로, 이 전략을 업그레이드하는 방법을 알아보겠습니다. 전략적 변화는 크지 않지만, 변화의 세부 사항에는 주의가 필요합니다. 코드의 일부 부분에 대한 정의가 이전과 변경되었으므로 이해할 필요가 있습니다.
A交易所->B交易所,B交易所->A交易所스프레드를 촉발하는 수평선을 그립니다. 우리는 직접 사용합니다画线类库장점은 간단하고 사용하기 쉽다는 것입니다. 여기서 FMZ를 사용하는 방법도 배울 것입니다.模版类库기능.다음으로, 이러한 디자인을 하나씩 구현해 보겠습니다.
Binance 현물 거래를 예로 들어 코드를 사용하여 현물 레버리지 모드로 전환합니다.exchanges[i].IO, 매개변수를 전달합니다trade_normal레버리지 포지션별로 전환하고 전달하세요.trade_super_margin레버리지 풀 포지션으로 전환하세요. 백테스팅은 지원되지 않습니다. 이는 실제 거래에서만 사용됩니다.
존재하다main함수 시작 부분에 다음 준비 단계를 추가합니다.
// 切换杠杆模式
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")
}
}
}
여기의 전략은 바이낸스 현물의 코인 대 코인 레버리지 모드를 전환하기 위한 코드만 추가하므로, 전략 매개변수에 설정된 스위치는 바이낸스 현물에만 유효합니다.
패키지된 도면 템플릿을 사용하는 것은 매우 간단합니다. 우리가 사용하는 템플릿의 이름은 다음과 같습니다.画线类库. FMZ 플랫폼 전략 광장에서 직접 검색하여 얻을 수 있습니다.

혹은 https://www.fmz.com/strategy/27293 링크를 직접 클릭하여 이 템플릿의 복사 페이지로 이동하세요.

버튼을 클릭하면 이 템플릿 라이브러리를 귀하의 전략 라이브러리로 복사할 수 있습니다.

그런 다음 정책 편집 페이지에서 템플릿 열에 필요한 템플릿 라이브러리를 확인할 수 있습니다. 확인란을 선택하고 정책을 저장하면 이 정책은 이 템플릿을 참조합니다. 여기서는 템플릿 라이브러리의 사용법을 간략하게 설명합니다. 이 전략은 이미 이 템플릿을 참조했으므로 작업을 반복할 필요가 없습니다. 이 전략을 Strategy Square에 복사한 후에는 전략 편집 페이지의 템플릿 열에서 해당 전략을 볼 수 있습니다.画线类库이미 인용됨.
우리는 주로 사용하는 방법을 배웁니다画线类库그래프를 그리는 함수.

우리는 계획하고 있습니다A->B가격차이는,B->A가격차이와 가격차이 트리거라인이 그려집니다. 위 그림과 같이 두 개의 곡선(A에서 B로의 현재 가격 차이, B에서 A로의 현재 가격 차이)과 두 개의 수평선(트리거 가격 차이 선)을 그려야 합니다.
우리는 일방적인 헤지를 설계해야 하기 때문에,A->B그리고B->A트리거 라인이 다릅니다. 이전 기사의 디자인은 더 이상 사용할 수 없습니다.
이전 기사에서:
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
트리거 스프레드는 하나뿐입니다.targetDiffPrice。
여기서 코드를 수정해야 합니다. 먼저 매개변수를 수정해야 합니다.

그런 다음 코드를 수정하세요.
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
}
이런 방식으로 가격 차이 트리거 라인이 이전과 다르게 변경됩니다.targetDiffPrice하나, 둘이 되다targetDiffPriceA2B、targetDiffPriceB2A。
다음으로, 선 그리기 라이브러리의 선 그리기 기능을 사용하여 이 데이터를 차트에 그릴 수 있습니다.
// 画图
$.PlotHLine(targetDiffPriceA2B, "A->B") // 该函数第一个参数是水平线在Y轴方向上的值,第二个参数是显示文本
$.PlotHLine(targetDiffPriceB2A, "B->A")
전략이 실행되면 이와 같은 차트가 나타납니다.

다음으로, 과도한 추첨을 방지하기 위해 실시간 스프레드 곡선을 그립니다. 실시간 가격 차이 데이터의 곡선을 그리는 코드를 잔액 확인에 넣으세요.
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轴方向上的值
}
이렇게 하면 4줄의 그리기 코드만으로 전략이 실행될 때 차트를 표시할 수 있습니다.
위에서 언급했듯이, 가격 차이 트리거 라인이 두 개로 변형되어 제어됩니다.A->B헤지 트리거B->A헤지가 발동되었습니다. 이 방법에서는 기존 주문 가격 알고리즘을 사용할 수 없으며 대신 시장 가격과 슬리피지 방법을 사용합니다.
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
}
}
매수가격과 매도가격이 두 개의 데이터로 분리되어 있으므로 헤지기능은hedge이것도 수정이 필요합니다.
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()
}
이러한 변경 사항을 기반으로 한 몇 가지 사소한 조정 사항도 있는데, 여기서는 다루지 않겠습니다. 자세한 내용은 코드를 보면 됩니다.
전략에 상호 작용성을 추가하여 전략이 스프레드 트리거 라인을 실시간으로 수정할 수 있도록 합니다. 이는 반자동 전략에 대한 설계 요구 사항이며, 여기서는 교육용 데모로 구현되었습니다. 전략 상호작용 디자인도 매우 간단합니다. 먼저 전략 편집 페이지에서 전략에 상호작용 컨트롤을 추가합니다.

두 개의 컨트롤이 추가되었습니다. 하나는 A2B이고 다른 하나는 B2A입니다. 컨트롤 입력 상자에 값을 입력한 후 입력 상자 오른쪽에 있는 버튼을 클릭합니다. 예를 들어, 입력 상자에 값을 입력하라는 지시가 전략에 즉시 전송됩니다.123, 클릭A2B이 버튼을 클릭하면 전략에 대한 지침이 즉시 전송됩니다.
A2B:123
전략 코드에서 상호작용 감지 및 처리 코드를 설계합니다.
// 交互
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])
}
}
}
상태 표시줄 데이터를 보다 체계적으로 정리하고 관찰하기 쉽게 만들었습니다.
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) + "`")

백테스팅은 단지 전략에 대한 테스트이자 기능에 대한 예비적 탐지일 뿐입니다. 실제로 많은 버그는 백테스팅 단계에서 테스트할 수 있습니다. 백테스트 결과에 너무 많은 주의를 기울일 필요는 없습니다. 최종 전략은 여전히 실제 환경에서 테스트되어야 합니다.


전략 소스 코드: https://www.fmz.com/strategy/302834