Recientemente, hay muchas estrategias Martingale discutidas en el grupo oficial de FMZ, y no hay muchas estrategias Martingale de contratos de criptomonedas en la plataforma. Por lo tanto, aproveché esta oportunidad para diseñar una estrategia Martingale simple para futuros de criptomonedas. ¿Por qué se llama estrategia Martingale? Debido a que los riesgos potenciales de la estrategia Martin no son pequeños, no está diseñada exactamente de acuerdo con la estrategia Martin. Sin embargo, este tipo de estrategia todavía tiene muchos riesgos, y los parámetros de configuración de la estrategia tipo Martin están estrechamente relacionados con el riesgo, y el riesgo no debe ignorarse.
Este artículo explica y aprende principalmente del diseño de estrategias de tipo Martin.
El capital total se utiliza a menudo al diseñar estrategias de futuros de criptomonedas. Esto se debe a que se deben calcular los rendimientos, especialmente cuando se necesitan calcular los rendimientos flotantes.exchange.GetAccount()
De hecho, la mayoría de los intercambios de futuros de criptomonedas proporcionan los datos del capital total, pero este atributo no está uniformemente empaquetado en FMZ.
Así que diseñamos funciones para obtener estos datos de acuerdo con diferentes intercambios:
// OKEX V5 obtain total equity
function getTotalEquity_OKEX_V5() {
var totalEquity = null
var ret = exchange.IO("api", "GET", "/api/v5/account/balance", "ccy=USDT")
if (ret) {
try {
totalEquity = parseFloat(ret.data[0].details[0].eq)
} catch(e) {
Log("failed to obtain the total equity of the account!")
return null
}
}
return totalEquity
}
// Binance futures
function getTotalEquity_Binance() {
var totalEquity = null
var ret = exchange.GetAccount()
if (ret) {
try {
totalEquity = parseFloat(ret.Info.totalWalletBalance)
} catch(e) {
Log("failed to obtain the total equity of the account!")
return null
}
}
return totalEquity
}
EltotalEquity
Entonces escribimos una función como la entrada de llamada, y llamamos a la función correspondiente de acuerdo con el nombre del intercambio.
function getTotalEquity() {
var exName = exchange.GetName()
if (exName == "Futures_OKCoin") {
return getTotalEquity_OKEX_V5()
} else if (exName == "Futures_Binance") {
return getTotalEquity_Binance()
} else {
throw "This exchange is not supported"
}
}
Antes de diseñar la función principal y la lógica principal, necesitamos hacer algunos preparativos y diseñar algunas funciones auxiliares.
Cancelar todas las órdenes pendientes actuales
function cancelAll() {
while (1) {
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
exchange.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
Sleep(500)
}
}
Esta función es familiar para aquellos que a menudo leen el código de ejemplo de estrategia en el cuadrado de estrategia FMZ, y muchas estrategias han utilizado diseños similares.
Operaciones de colocación de futuros
function trade(distance, price, amount) {
var tradeFunc = null
if (distance == "buy") {
tradeFunc = exchange.Buy
} else if (distance == "sell") {
tradeFunc = exchange.Sell
} else if (distance == "closebuy") {
tradeFunc = exchange.Sell
} else {
tradeFunc = exchange.Buy
}
exchange.SetDirection(distance)
return tradeFunc(price, amount)
}
function openLong(price, amount) {
return trade("buy", price, amount)
}
function openShort(price, amount) {
return trade("sell", price, amount)
}
function coverLong(price, amount) {
return trade("closebuy", price, amount)
}
function coverShort(price, amount) {
return trade("closesell", price, amount)
}
Hay cuatro direcciones para el comercio de futuros: openLong, openShort, coverLong y coverShort. Así que diseñamos cuatro funciones de orden correspondientes a estas operaciones. Si usted considera sólo el pedido, entonces hay varios factores necesarios: dirección, precio del pedido y volumen del pedido.
Así que también diseñamos una función llamada:trade
para manejar la operación cuandodistance
, price
, amount
se especifican.
Las llamadas de la función a openLong, openShort, coverLong y coverShort se completan en última instancia por eltrade
función, es decir, colocar una orden en un intercambio de futuros basado en la distancia, el precio y la cantidad establecidos.
La idea de la estrategia es muy simple, tomar el precio actual como la línea de base, y colocar órdenes de venta (corto) y compra (largo) a una cierta distancia hacia arriba o hacia abajo. Una vez que se completa la transacción, todas las órdenes restantes serán canceladas, y luego se colocará una nueva orden de cierre a una cierta distancia de acuerdo con el precio de la posición, y se colocará una orden de aumento al precio actual actualizado, pero el volumen de la orden no se duplicará para posiciones adicionales.
Trabajos iniciales Debido a la orden pendiente, necesitamos dos variables globales para registrar la ID de la orden.
var buyOrderId = null
var sellOrderId = null
Luego, los parámetros de la interfaz de estrategia están diseñados para usar la opción de bot simulado OKEX_V5, por lo que se necesita realizar algún procesamiento en el código:
var exName = exchange.GetName()
// Switch OKEX V5 simulated bot
if (isSimulate && exName == "Futures_OKCoin") {
exchange.IO("simulate", true)
}
También hay una opción para restablecer toda la información en los parámetros de la interfaz, por lo que debe haber un procesamiento correspondiente en el código:
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("reset all data", "#FF0000")
}
Solo tenemos contratos perpetuos, así que la escritura está fija aquí y sólo está fijada en perpetuo.
exchange.SetContractType("swap")
Entonces también necesitamos considerar la precisión del precio del pedido y el monto del pedido. Si la precisión no se establece correctamente, la precisión se perderá durante el proceso de cálculo de la estrategia. Si los datos tienen un gran número de decimales, es fácil hacer que el pedido sea rechazado por la interfaz de intercambio.
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("set precision", pricePrecision, amountPrecision)
Recuperación de datos sencilla por diseño
if (totalEq == -1 && !IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "failed to obtain initial equity"
}
} else {
totalEq = recoverTotalEq
}
}
Si desea especificar el capital total inicial de la cuenta cuando la estrategia se está ejecutando, se puede establecer el parámetrototalEq
Si este parámetro está establecido en -1, la estrategia leerá los datos de capital total almacenados. Si no hay datos de capital total almacenados, el capital total leído actual se utiliza como el capital total inicial de la estrategia en curso. Después de eso, un aumento en el capital total indica una ganancia, y una disminución en el capital total indica una pérdida. Si se leen los datos de capital total, la estrategia continuará ejecutándose con estos datos.
La lógica principal Después de que el trabajo inicial está hecho, finalmente llegamos a la parte lógica principal de la estrategia. Para mayor comodidad de explicación, escribí las instrucciones directamente en los comentarios del código.
while (1) { // The main logic of the strategy is designed as an infinite loop
var ticker = _C(exchange.GetTicker) // Read the current market information first, mainly using the latest transaction price
var pos = _C(exchange.GetPosition) // Read current position data
if (pos.length > 1) { // Judging the position data, because of the logic of this strategy, it is unlikely that long and short positions will appear at the same time, so if there are long and short positions at the same time, an error will be thrown
Log(pos)
throw "Simultaneous long and short positions" // Throw an error to stop the strategy
}
//Depends on status
if (pos.length == 0) { // Make different operations according to the position status, when there is no position, pos.length == 0
// If you have not held a position, count the profit once
if (!IsVirtual()) {
var currTotalEq = getTotalEquity()
if (currTotalEq) {
LogProfit(currTotalEq - totalEq, "current total equity:", currTotalEq)
}
}
buyOrderId = openLong(ticker.Last - targetProfit, amount) // Open a buy order for a long position
sellOrderId = openShort(ticker.Last + targetProfit, amount) // Open a short sell order
} else if (pos[0].Type == PD_LONG) { // For long positions, the position and quantity of pending orders are different
var n = 1
var price = ticker.Last
buyOrderId = openLong(price - targetProfit * n, amount)
sellOrderId = coverLong(pos[0].Price + targetProfit, pos[0].Amount)
} else if (pos[0].Type == PD_SHORT) { // For short positions, the position and quantity of pending orders are different
var n = 1
var price = ticker.Last
buyOrderId = coverShort(pos[0].Price - targetProfit, pos[0].Amount)
sellOrderId = openShort(price + targetProfit * n, amount)
}
if (!sellOrderId || !buyOrderId) { // If one side of the pending order fails, cancel all pending orders and start over
cancelAll()
buyOrderId = null
sellOrderId = null
continue
}
while (1) { // The pending order is completed, start monitoring the order
var isFindBuyId = false
var isFindSellId = false
var orders = _C(exchange.GetOrders)
for (var i = 0 ; i < orders.length ; i++) {
if (buyOrderId == orders[i].Id) {
isFindBuyId = true
}
if (sellOrderId == orders[i].Id) {
isFindSellId = true
}
}
if (!isFindSellId && !isFindBuyId) { // Detected that both buy and sell orders have been filled
cancelAll()
break
} else if (!isFindBuyId) { // Detected buy order closing
Log("buy order closing")
cancelAll()
break
} else if (!isFindSellId) { // Detected sell order closing
Log("sell order closing")
cancelAll()
break
}
LogStatus(_D())
Sleep(3000)
}
Sleep(500)
}
Toda la lógica y el diseño se explican.
Dejemos que la estrategia pase por un mercado del 19 de mayo.
Se puede ver que la estrategia Martingale todavía tiene ciertos riesgos.
El bot real se puede ejecutar con el bot de simulación OKEX V5
Dirección estratégica:https://www.fmz.com/strategy/294957
Las estrategias se usan principalmente para aprender, y el dinero real debe usarse con precaución~!