
En el artículo anterior, implementamos una estrategia de cobertura simple. A continuación, aprenderemos cómo mejorar esta estrategia. Los cambios de estrategia no serán importantes, pero los detalles de los cambios requieren atención. Las definiciones de algunas partes del código han cambiado respecto a antes y es necesario comprenderlas.
A交易所->B交易所,B交易所->A交易所Dibuje la línea horizontal que desencadena la propagación. Nosotros utilizamos directamente画线类库La ventaja es que es simple y fácil de usar. Aquí también aprenderemos a usar FMZ.模版类库Función.A continuación, implementemos estos diseños uno por uno.
Tomando el trading spot de Binance como ejemplo, cambie al modo de apalancamiento spot usando el códigoexchanges[i].IO, pasar parámetrostrade_normalCambie a posición por posición apalancada y pasetrade_super_marginCambiar a posición completa apalancada, no se admite el backtesting. Esto sólo se utiliza en el comercio real.
existirmainLa fase de preparación al inicio de la función se incrementa:
// 切换杠杆模式
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")
}
}
}
La estrategia aquí solo agrega el código para cambiar el modo de apalancamiento de moneda a moneda para Binance spot, por lo que el cambio establecido en los parámetros de la estrategia solo es válido para Binance spot.
Es muy sencillo utilizar las plantillas de dibujo incluidas. La plantilla que utilizamos se llama画线类库. Podrás buscarlo y obtenerlo directamente en la plaza de estrategia de la plataforma FMZ.

O haga clic directamente en el enlace: https://www.fmz.com/strategy/27293 para ir a la página de copia de esta plantilla.

Haga clic en el botón para copiar esta biblioteca de plantillas a su propia biblioteca de estrategias.

Luego, en la página de edición de políticas, puedes verificar la biblioteca de plantillas que necesitas en la columna de plantillas. Después de marcar la casilla y guardar la política, esta política hará referencia a esta plantilla. Aquí simplemente explicamos brevemente el uso de la biblioteca de plantillas. Esta estrategia ya ha hecho referencia a esta plantilla, por lo que no es necesario repetir la operación. Después de copiar esta estrategia en Strategy Square, podrás verla en la columna de plantilla de la página de edición de estrategia.画线类库Ya citado.
Aprendemos principalmente a utilizar画线类库Función para dibujar la gráfica.

Estamos planeandoA->BLa diferencia de precio,B->ASe dibujan la diferencia de precio y la línea de activación de la diferencia de precio. Es necesario dibujar dos curvas (la diferencia de precio actual de A a B y de B a A) y dos líneas horizontales (líneas de diferencia de precio de activación), como se muestra en la figura de arriba.
Porque necesitamos diseñar una cobertura unilateral,A->ByB->ALa línea de activación es diferente. El diseño del artículo anterior ya no se puede utilizar.
En el artículo anterior:
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Solo hay un diferencial de activacióntargetDiffPrice。
Entonces aquí necesitamos modificar el código, primero modificar los parámetros.

Luego modifica el código:
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
}
De esta manera, la línea de activación de la diferencia de precio cambia respecto a la anterior.targetDiffPriceUno, se convirtió en dostargetDiffPriceA2B、targetDiffPriceB2A。
A continuación, puede utilizar la función de dibujo de líneas de la biblioteca de dibujo de líneas para dibujar estos datos en el gráfico.
// 画图
$.PlotHLine(targetDiffPriceA2B, "A->B") // 该函数第一个参数是水平线在Y轴方向上的值,第二个参数是显示文本
$.PlotHLine(targetDiffPriceB2A, "B->A")
Cuando la estrategia esté en ejecución, aparecerá un gráfico como éste.

A continuación, dibuje la curva de spread en tiempo real para evitar sobregirar. Coloque el código para dibujar curvas de datos de diferencia de precios en tiempo real en la verificación de saldo.
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轴方向上的值
}
De esta manera, con solo 4 líneas de código de dibujo, la estrategia puede mostrar un gráfico cuando se está ejecutando.
Como se mencionó anteriormente, la línea de activación de la diferencia de precio se ha transformado en dos, controlandoA->BEl gatillo de la coberturaB->ALa cobertura se activa. De esta manera, no se puede utilizar el algoritmo de precio de orden anterior y en su lugar se utiliza el método de precio de mercado más deslizamiento.
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
}
}
Dado que los precios de compra y venta se separan en dos datos, la función de coberturahedgeTambién es necesario modificarlo.
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()
}
También hay algunos ajustes menores basados en estos cambios, en los que no entraré aquí. Puedes consultar el código para obtener más detalles.
Agregue interactividad a la estrategia para que esta pueda modificar la línea de activación del spread en tiempo real. Este es un requisito de diseño para una estrategia semiautomática, que también se implementa aquí como demostración didáctica. El diseño de la interacción de la estrategia también es muy sencillo. Primero, agregue controles interactivos a la estrategia en la página de edición de la estrategia.

Se añaden dos controles, uno llamado A2B y otro llamado B2A. Después de ingresar un valor en el cuadro de entrada de control, haga clic en el botón en el lado derecho del cuadro de entrada. Se enviará inmediatamente una instrucción a la estrategia, por ejemplo: ingrese un valor en el cuadro de entrada123, haga clicA2BEste botón enviará inmediatamente instrucciones a la estrategia.
A2B:123
Diseñar código de detección y procesamiento de interacción en el código de estrategia.
// 交互
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])
}
}
}
Haga que los datos de la barra de estado estén más organizados y sean más fáciles de observar.
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) + "`")

El backtesting es solo una prueba de estrategia y una detección preliminar de funciones. Muchos errores pueden ser realmente detectados durante la etapa de backtesting. No es necesario prestar demasiada atención a los resultados de las pruebas retrospectivas. La estrategia final aún debe probarse en un entorno real.


Código fuente de la estrategia: https://www.fmz.com/strategy/302834