Em resposta às necessidades de muitos usuários, a plataforma FMZ recentemente apoiou a plataforma descentralizada dYdX. Amigos com estratégias podem minerar na dYdX felizmente. Há muito tempo, eu queria escrever uma estratégia de negociação aleatória. Não importa se eu ganhe ou não. O objetivo é praticar minha técnica e ensinar o design de estratégia a propósito. Então, em seguida, vamos projetar uma estratégia de plataforma aleatória juntos. Não se preocupe com o desempenho da estratégia e apenas aprenda o design de estratégia.
A captura de tela da estratégia de mineração no artigo.
Bem-vindos amigos que têm boas ideias de estratégia de mineração para compartilhar!
Vamos fazer um brainstorming! Planejamos projetar uma estratégia para colocar ordens aleatoriamente sem olhar para indicadores ou preços. Ordenar não é nada mais do que fazer longo e curto, que é apostar na probabilidade. Então usamos números aleatórios de 1 a 100 para determinar se fazer longo ou fazer curto.
Condição de fazer long: números aleatórios de 1 a 50. Condição de fazer curto: números aleatórios de 51 a 100.
Para fazer longo e curto, ambos precisam de 50 números. Em seguida, vamos pensar em como fechar posições. Como é uma aposta, deve haver um padrão de ganhar ou perder. Então, vamos definir um stopProfit fixo e stopLoss como padrão de ganhar ou perder. Tomemos o stopProfit como ganhar e o stopLoss como perder. Quanto à adequação do stopProfit e stopLoss, ele realmente afeta a proporção de lucro e perda, e a taxa de ganho também! (É eficaz projetar uma estratégia dessa maneira? É garantido que seja uma expectativa matemática positiva? De qualquer forma, vamos fazê-lo primeiro! Porque é para aprendizado e pesquisa!)
A negociação não é livre de custos, e há fatores como slipppoint e taxas que são suficientes para puxar nossa taxa de ganho de negociação aleatória para o lado de menos de 50%. Pensando nisso, como continuar o projeto a partir daqui? É melhor projetar a escalagem por múltiplos para aumentar as posições. Uma vez que é uma aposta, a probabilidade de perder 10 ou 8 vezes sucessivamente não deve ser muito grande. Então eu quero projetar colocando um pequeno valor de ordem no primeiro comércio, o menor possível. Então, se eu perder a aposta, aumentar o valor da ordem e continuar a colocar ordens aleatórias.
A estratégia é tão simples quanto isto.
Código de origem do desenho:
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 da estratégia:
A estratégia precisa de um nome, e vamos chamá-lo "Adivinha qual é maior (versão dYdX).
O backtest é apenas para referência! É principalmente para verificar se há algum bug na estratégia; backtest com Binance Futures.
O backtest acabou, não há bugs, mas sinto que o sistema de backtest foi combinado... vamos executá-lo num robô real para observação.
Esta estratégia é apenas para aprendizagem e referência.Não.!! Não.Use-o num robô de verdade!