En respuesta a las necesidades de muchos usuarios, la plataforma FMZ recientemente ha apoyado la plataforma descentralizada dYdX. Los amigos con estrategias pueden minar en dYdX felizmente. Hace mucho tiempo, quería escribir una estrategia de trading aleatoria. No importa si gano o no. El propósito es practicar mi técnica y enseñar el diseño de estrategia por cierto.
La captura de pantalla de la estrategia minera en el artículo.
¡Bienvenidos los amigos que tienen buenas ideas de estrategia minera para compartir!
Vamos a tener una lluvia de ideas! Planeamos diseñar una estrategia para colocar órdenes al azar sin mirar indicadores o precios. Ordenar no es más que hacer largo y corto, que es apostar a la probabilidad. Luego usamos números aleatorios de 1 a 100 para determinar si hacer largo o hacer corto.
Condición de hacer largo: números aleatorios de 1 a 50. Condición de hacer corto: números aleatorios de 51 a 100.
Para hacer largo y corto, ambos necesitan 50 números. A continuación, pensemos en cómo cerrar posiciones. Ya que es una apuesta, debe haber un estándar ganador o perdedor. Luego, establezcamos un stopProfit fijo y un stopLoss como el estándar de ganar o perder. Tomemos stopProfit como ganar y stopLoss como perder. En cuanto a la idoneidad de stopProfit y stopLoss, en realidad afecta la relación de ganancias y pérdidas, y la tasa de ganancias también! (¿Es efectivo diseñar una estrategia de esta manera? ¿Se puede garantizar que sea una expectativa matemática positiva? De todos modos, hagámoslo primero! ¡Porque es para aprender y investigar!)
El comercio no es libre de costos, y hay factores como el punto de deslizamiento y las tarifas que son suficientes para tirar nuestra tasa de ganancia de comercio aleatorio al lado de menos del 50%. Pensando en eso, ¿cómo continuar el diseño de aquí? Es mejor diseñar escalar por múltiples para aumentar las posiciones. Como es una apuesta, la probabilidad de perder sucesivamente 10 u 8 veces no debe ser muy grande. Así que quiero diseñar colocando una pequeña cantidad de orden en la primera operación, tan pequeña como sea posible. Luego, si pierdo la apuesta, aumentar la cantidad de orden y continuar colocando órdenes al azar.
La estrategia está bien, tan simple como esto.
Código fuente del diseño:
var openPrice = 0
var ratio = 1
var totalEq = null
var nowEq = null
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)
}
}
function main() {
if (isReset) {
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("reset all data", "#FF0000")
}
exchange.SetContractType(ct)
var initPos = _C(exchange.GetPosition)
if (initPos.length != 0) {
throw "Position detected when starting the strategy!"
}
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("setPrecision", pricePrecision, amountPrecision)
if (!IsVirtual()) {
var recoverTotalEq = _G("totalEq")
if (!recoverTotalEq) {
var currTotalEq = _C(exchange.GetAccount).Balance // equity
if (currTotalEq) {
totalEq = currTotalEq
_G("totalEq", currTotalEq)
} else {
throw "fail to obtain the initial equity"
}
} else {
totalEq = recoverTotalEq
}
} else {
totalEq = _C(exchange.GetAccount).Balance
}
while (1) {
if (openPrice == 0) {
// update account information, and calculate the profit
var nowAcc = _C(exchange.GetAccount)
nowEq = IsVirtual() ? nowAcc.Balance : nowAcc.Balance // equity
LogProfit(nowEq - totalEq, nowAcc)
var direction = Math.floor((Math.random()*100)+1) // 1~50 , 51~100
var depth = _C(exchange.GetDepth)
if (depth.Asks.length <= 2 || depth.Bids.length <= 2) {
Sleep(1000)
continue
}
if (direction > 50) {
// long
openPrice = depth.Bids[1].Price
exchange.SetDirection("buy")
exchange.Buy(Math.abs(openPrice) + slidePrice, amount * ratio)
} else {
// short
openPrice = -depth.Asks[1].Price
exchange.SetDirection("sell")
exchange.Sell(Math.abs(openPrice) - slidePrice, amount * ratio)
}
Log("place", direction > 50 ? "buy order" : "sell order", ",price:", Math.abs(openPrice))
continue
}
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
var pos = _C(exchange.GetPosition)
if (pos.length == 0) {
openPrice = 0
continue
}
// detect close positions
while (1) {
var depth = _C(exchange.GetDepth)
if (depth.Asks.length <= 2 || depth.Bids.length <= 2) {
Sleep(1000)
continue
}
var stopLossPrice = openPrice > 0 ? Math.abs(openPrice) - stopLoss : Math.abs(openPrice) + stopLoss
var stopProfitPrice = openPrice > 0 ? Math.abs(openPrice) + stopProfit : Math.abs(openPrice) - stopProfit
var winOrLoss = 0 // 1 win , -1 loss
// plot
$.PlotLine("bid", depth.Bids[0].Price)
$.PlotLine("ask", depth.Asks[0].Price)
// stop loss
if (openPrice > 0 && depth.Bids[0].Price < stopLossPrice) {
exchange.SetDirection("closebuy")
exchange.Sell(depth.Bids[0].Price - slidePrice, pos[0].Amount)
winOrLoss = -1
} else if (openPrice < 0 && depth.Asks[0].Price > stopLossPrice) {
exchange.SetDirection("closesell")
exchange.Buy(depth.Asks[0].Price + slidePrice, pos[0].Amount)
winOrLoss = -1
}
// stop profit
if (openPrice > 0 && depth.Bids[0].Price > stopProfitPrice) {
exchange.SetDirection("closebuy")
exchange.Sell(depth.Bids[0].Price - slidePrice, pos[0].Amount)
winOrLoss = 1
} else if (openPrice < 0 && depth.Asks[0].Price < stopProfitPrice) {
exchange.SetDirection("closesell")
exchange.Buy(depth.Asks[0].Price + slidePrice, pos[0].Amount)
winOrLoss = 1
}
// detect pending orders
Sleep(2000)
var orders = _C(exchange.GetOrders)
if (orders.length == 0) {
pos = _C(exchange.GetPosition)
if (pos.length == 0) {
if (winOrLoss == -1) {
ratio++
} else if (winOrLoss == 1) {
ratio = 1
}
break
}
} else {
// cancel pending orders
cancelAll()
Sleep(2000)
pos = _C(exchange.GetPosition)
// after canceling, update positions, which needs to be detected again
if (pos.length == 0) {
if (winOrLoss == -1) {
ratio++
} else if (winOrLoss == 1) {
ratio = 1
}
break
}
}
var tbl = {
"type" : "table",
"title" : "info",
"cols" : ["totalEq", "nowEq", "openPrice", "bid1Price", "ask1Price", "ratio", "pos.length"],
"rows" : [],
}
tbl.rows.push([totalEq, nowEq, Math.abs(openPrice), depth.Bids[0].Price, depth.Asks[0].Price, ratio, pos.length])
tbl.rows.push(["pos", "type", "amount", "price", "--", "--", "--"])
for (var j = 0 ; j < pos.length ; j++) {
tbl.rows.push([j, pos[j].Type, pos[j].Amount, pos[j].Price, "--", "--", "--"])
}
LogStatus(_D(), "\n", "`" + JSON.stringify(tbl) + "`")
}
} else {
// cancel pending orders
// reset openPrice
cancelAll()
openPrice = 0
}
Sleep(1000)
}
}
Parámetros de la estrategia:
La estrategia necesita un nombre, y vamos a llamarlo "Adivina cuál es más grande (versión dYdX).
¡La prueba de retroceso es sólo para referencia! Es principalmente para comprobar si hay algún error en la estrategia; backtest con Binance Futures.
La prueba de retroceso ha terminado, no hay errores, pero siento que el sistema de retroceso fue emparejado... vamos a ejecutarlo en un bot real para observación.
Esta estrategia es sólo para aprendizaje y referencia.No lo hagas!! No lo hagas¡ Usarlo en un robot de verdad!