En el artículo anterior, implementamos una estrategia de cobertura simple juntos, y luego aprenderemos cómo actualizar esta estrategia. Los cambios de estrategia no son grandes, pero los detalles de los cambios necesitan atención.
A exchange -> B exchange
, B exchange -> A exchange
, y dibujar la línea horizontal que desencadena la propagación.line drawing class library
En el caso de las empresas de la industria de la información, la ventaja es que es fácil de usar, aquí también aprendemos a utilizar eltemplate class library
función de la FMZ.A continuación, implementemos estos diseños uno por uno.
Tome Binance spot real bot como ejemplo, cambiar al modo apalancado spot, utilizar el códigoexchanges[i].IO
, introduzca el parámetrotrade_normal
para cambiar a la posición de apalancamiento por posición, y entradatrade_super_margin
Para cambiar a apalancamiento de posición completa, backtesting no es compatible.
Añadir a la fase de preparación al comienzo de lamain
Función:
// Switch leverage mode
for (var i = 0 ; i < exchanges.length ; i++) { // Traverse and detect all added exchange objects
if (exchanges[i].GetName() == "Binance" && marginType != 0) { //If the exchange object represented by the current i-index is Binance spot, and the parameter marginType of the strategy interface is not the option of "common currency", execute the switch operation
if (marginType == 1) {
Log(exchanges[i].GetName(), "Set to leveraged position-by-position")
exchanges[i].IO("trade_normal")
} else if (marginType == 2) {
Log(exchanges[i].GetName(), "Set to leveraged full position")
exchanges[i].IO("trade_super_margin")
}
}
}
La estrategia aquí solo agrega el código para cambiar el modo de apalancamiento de moneda a moneda de Binance spot, por lo que la configuración del interruptor en los parámetros de la estrategia solo es válida para Binance spot.
Es muy fácil de usar la plantilla de dibujo ya envuelto.Line Drawing Library
Se puede obtener buscando directamente en el cuadrado de estrategia de la plataforma FMZ.
O haga clic en el enlace directamente:https://www.fmz.com/strategy/27293para saltar a la página de copia de esta plantilla.
Haga clic en el botón para copiar esta biblioteca de clases de plantilla en su propia biblioteca de estrategias.
Luego puede comprobar la biblioteca de clases de plantilla a utilizar en la columna de plantilla en la página de edición de estrategia. Guarde la estrategia después de comprobarla, y la estrategia se referirá a esta plantilla. Esta es solo una breve descripción del uso de la biblioteca de clases de plantilla. Esta estrategia ya ha hecho referencia a esta plantilla, por lo que no es necesario repetir la operación. Cuando copia esta estrategia en el cuadrado de estrategia, puede ver queLine Drawing Library
se ha hecho referencia en la barra de plantillas de la página de edición de estrategias.
Aprenderemos sobre todo cómo utilizar las funciones de laLine Drawing Library
para dibujar un gráfico.
Planeamos dibujar la propagación deA->B
, la propagación deB->A
, y la línea de disparo de la propagación. necesitamos dibujar dos curvas (actual A a B, B a A propagación), dos líneas horizontales (línea de disparo de la propagación), como se muestra en la figura anterior.
Porque queremos diseñar cobertura unilateral, las líneas de disparo deA->B
yB->A
No podemos usar el diseño del artículo anterior.
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
}
Sólo hay un disparador de propagacióntargetDiffPrice
¿ Qué pasa?
Así que aquí tenemos que transformar el código, transformar los parámetros primero.
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 diferencia línea de disparo ha cambiado de la anteriortargetDiffPrice
A las dos.targetDiffPriceA2B
, targetDiffPriceB2A
¿ Qué pasa?
El siguiente paso es dibujar estos datos en el gráfico utilizando la función de línea de dibujo de la biblioteca de dibujo de líneas.
// drawing
$.PlotHLine(targetDiffPriceA2B, "A->B") // The first parameter of this 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")
Cuando la estrategia se está ejecutando, hay un gráfico como este.
A continuación, dibuja la curva de dispersión en tiempo real, para evitar sobre dibujar la línea.
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) // Draw real-time spread curves
$.PlotLine("B2A", depthB.Bids[0].Price - depthA.Asks[0].Price) // The first parameter is the name of the curve, and the second parameter is the value of the curve at the current moment, that is, the value in the Y-axis direction at the current moment
}
De esta manera, el código de dibujo es de solo 4 líneas, lo que permite que la estrategia tenga un gráfico mostrado en tiempo de ejecución.
Como se ha mencionado anteriormente, la línea de activación del diferencial se ha modificado en dos, controlando la línea de activación de cobertura deA->B
yB->A
De esta manera, no se puede utilizar el algoritmo del precio de la orden anterior, y en su lugar se utiliza el método de adición del precio de entrada al precio de mercado.
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPriceA2B && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A -> B market conditions are met
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("trigger A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[1].Balance * 0.8 / priceSell, nowAccs[0].Stocks) // Tips
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 conditions are met
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("trigger B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, priceBuy, priceSell, amount, nowAccs[0].Balance * 0.8 / priceBuy, nowAccs[1].Stocks) //Tips
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 coberturahedge
También debe modificarse.
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, que no se repetirán aquí.
Añadir interacción a la estrategia, para que la estrategia pueda modificar la línea de disparo de propagación en tiempo real. El diseño de la estrategia de interacción también es muy simple. Primero, añadir controles de interacción a la estrategia en la página de edición de la estrategia.
Añadido dos controles, uno llamado A2B y otro llamado B2A. Después de introducir un valor en el cuadro de entrada de control, haga clic en el botón a la derecha del cuadro de entrada. Una instrucción se enviará a la estrategia inmediatamente, por ejemplo: introducir el valor123
En el cuadro de entrada, haga clic enA2B
botón, y una instrucción será enviada a la estrategia inmediatamente.
A2B:123
Diseñar código de detección y procesamiento interactivo en el código de estrategia.
// interact
var cmd = GetCommand() // Every time the loop is executed here, it checks whether there is an interactive command, and returns to an empty string if not.
if (cmd) { // An interactive command was detected, such as A2B:123
Log("command received:", cmd)
var arr = cmd.split(":") // Split out the interactive control name and the value in the input box, arr[0] is A2B, arr[1] is 123
if (arr[0] == "A2B") { // Determine whether the triggered interactive control is A2B
Log("Modify the parameters of A2B, ", diffAsPercentage ? "The parameter is the difference percentage" : "The parameter is the difference:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageB2A = parseFloat(arr[1]) // Modify the trigger spread line
} else {
hedgeDiffPriceA2B = parseFloat(arr[1]) // Modify the trigger spread line
}
} else if (arr[0] == "B2A") { // Triggered control detected is B2A
Log("Modify the parameters of B2A, ", diffAsPercentage ? "The parameter is the difference percentage" : "The parameter is the difference:", arr[1])
if (diffAsPercentage) {
hedgeDiffPercentageA2B = parseFloat(arr[1])
} else {
hedgeDiffPriceB2A = parseFloat(arr[1])
}
}
}
Haga que la muestra de datos de la barra de estado sea más organizada y fácil de observar.
var tbl = {
"type" : "table",
"title" : "data",
"cols" : ["exchange", "coin", "freeze coin", "denominated currency", "freeze denominated currency", "trigger spread", "current spread"],
"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 sólo una estrategia de prueba, una función de detección preliminar, y muchos errores pueden ser probados en la etapa de backtesting en realidad.
Código fuente de la estrategia:https://www.fmz.com/strategy/302834