
Em resposta a muitas demandas de usuários, a plataforma FMZ recentemente deu suporte à exchange descentralizada dYdX. Amigos com estratégias podem minerar dYdX com alegria. Acontece que eu queria escrever uma estratégia de negociação aleatória há muito tempo. Não importava se eu ganhasse ou perdesse dinheiro. O propósito era praticar e ensinar design de estratégia ao mesmo tempo. Então, vamos projetar uma estratégia de troca aleatória juntos. Não se preocupe com o desempenho da estratégia. Vamos apenas aprender sobre design de estratégia.
Captura de tela da mineração estratégica neste artigo.

Amigos que tenham boas ideias de estratégias de mineração também são bem-vindos para deixar uma mensagem!
Vamos “pensar selvagemente”! Planejo criar uma estratégia que faça ordens aleatoriamente, sem olhar para indicadores ou preços. Ordens nada mais são do que ir longo ou curto, e tudo o que você precisa fazer é prever probabilidades. Em seguida, usamos números aleatórios de 1 a 100 para determinar posições longas e curtas.
Condições longas: números aleatórios de 1 a 50. Condições de venda a descoberto: números aleatórios de 51 a 100.
Os números para posições longas e curtas são 50. Em seguida, vamos pensar em como fechar a posição. Como é uma aposta, deve haver um padrão para ganhar e perder. Então, na transação, definimos take-profit e stop-loss fixos como o padrão para ganhar ou perder. Se você parar o lucro, você ganha; se você parar o prejuízo, você perde. Quanto às configurações adequadas de take-profit e stop-loss, isso realmente afeta a relação de lucros e perdas, ah sim! Isso também afeta a taxa de vitórias! (Essa estratégia de design é eficaz? Ela pode garantir uma expectativa matemática positiva? Vamos fazer isso primeiro! Afinal, é para aprendizado e pesquisa!)
Negociar não é isento de custos. Fatores como slippage e taxas de manuseio são suficientes para puxar nossa taxa de ganho de negociação aleatória para menos de 50%. Como devo continuar projetando com isso em mente? É melhor projetar um aumento de posição múltipla. Como é uma aposta, a probabilidade de perder 8 transações aleatórias de 10 em uma fileira não deve ser muito alta. Então, quero projetar a primeira transação para ter um tamanho de pedido muito pequeno, o menor possível. Então, se você perder a aposta, aumente a quantidade do pedido e continue fazendo pedidos aleatórios.
OK, o design da estratégia é simples assim.
Código fonte do design:
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("重置所有数据", "#FF0000")
}
exchange.SetContractType(ct)
var initPos = _C(exchange.GetPosition)
if (initPos.length != 0) {
throw "策略启动时有持仓!"
}
exchange.SetPrecision(pricePrecision, amountPrecision)
Log("设置精度", 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 "获取初始权益失败"
}
} else {
totalEq = recoverTotalEq
}
} else {
totalEq = _C(exchange.GetAccount).Balance
}
while (1) {
if (openPrice == 0) {
// 更新账户信息,计算收益
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("下", direction > 50 ? "买单" : "卖单", ",价格:", 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
}
// 平仓检测
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
// 画线
$.PlotLine("bid", depth.Bids[0].Price)
$.PlotLine("ask", depth.Asks[0].Price)
// 止损
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
}
// 止盈
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
}
// 检测挂单
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 {
// 撤销挂单
cancelAll()
Sleep(2000)
pos = _C(exchange.GetPosition)
// 撤销后更新持仓,需要再次检查
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 {
// 撤销挂单
// 重置openPrice
cancelAll()
openPrice = 0
}
Sleep(1000)
}
}
Parâmetros de estratégia:

Oh sim! A estratégia precisa de um nome, vamos chamá-la de “Adivinhe o tamanho (versão dYdX)”.
O backtesting é apenas para referência._<! O objetivo principal é verificar se há algum bug na estratégia e usar o backtesting da Binance Futures.




O backtesting foi concluído, sem bugs. Mas sinto que posso ter ajustado demais o sistema de backtest…T_T, deixe-me testar em tempo real.



Esta estratégia é apenas para aprendizado e referência.10 milhões~10 milhõesNão use isso de verdade! !