Exemplo de projeto de estratégia dYdX

Autora:Lydia., Criado: 2022-11-07 10:59:29, Atualizado: 2023-09-15 21:03:43

img

Em resposta à demanda de muitos usuários, a plataforma FMZ acessou recentemente o dYdX, uma exchange descentralizada. Alguém que tenha estratégias pode desfrutar do processo de aquisição da moeda digital dYdX. Eu só queria escrever uma estratégia de negociação estocástica há muito tempo, não importa se ela gera lucros. Então, a seguir, nos reunimos para projetar uma estratégia de troca estocástica, não importa se a estratégia funciona bem ou não, nós apenas aprendemos o design da estratégia.

Projeto de estratégia de negociação estocástica

Vamos fazer um brainstorming! É planejado projetar uma estratégia de colocar ordens aleatoriamente com indicadores e preços aleatórios. Colocar ordens não é nada mais do que ir longo ou curto, apenas apostando na probabilidade. Então usaremos o número aleatório 1 ~ 100 para determinar se vamos longo ou curto.

Condição para fazer a compra: número aleatório de 1 a 50. Condição para a aquisição curta: número aleatório 51~100.

Assim, tanto o longo quanto o curto são 50 números. Em seguida, vamos pensar em como fechar a posição, já que é uma aposta, então deve haver um critério para ganhar ou perder. Nós definimos um critério para stop fixed de lucro e perda na transação. Stop profit para a vitória, stop loss para a perda. Quanto à quantidade de stop profit e perda, é realmente o impacto da relação de lucro e perda, oh sim! Também afeta a taxa de ganho! (Este design de estratégia é eficaz? Pode ser garantido como uma expectativa matemática positiva? Faça primeiro! (Depois, é apenas para aprender, pesquisar!)

A negociação não é livre de custos, há deslizamento suficiente, taxas, etc. para puxar nossa taxa de ganho de negociação estocástica para o lado de menos de 50%. Então, como projetá-lo continuamente? Como se desenhar um multiplicador para aumentar a posição? Como é uma aposta, então a probabilidade de perder por 8 ~ 10 vezes em uma linha de negócios aleatórios deve ser baixa. Então a primeira transação foi projetada para colocar uma pequena quantidade de ordens, o menor possível. Então, se eu perder, eu vou aumentar a quantidade de ordens e continuar a colocar ordens aleatoriamente.

A estratégia é simples.

Código de origem concebido:

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 "Strategy starts with a position!"
    }
    
    exchange.SetPrecision(pricePrecision, amountPrecision)
    Log("set the pricePrecision", 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 "failed to obtain initial interest"
            }
        } else {
            totalEq = recoverTotalEq
        }
    } else {
        totalEq = _C(exchange.GetAccount).Balance
    }
    
    while (1) {
        if (openPrice == 0) {
            // Update account information and calculate profits
            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 ? "buying order" : "selling 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
            }
            
            // Test for closing the position
            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 
                
                // drawing the line
                $.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
                }
                
                // Test the 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)
                    // update the position after cancellation, and check it 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 the pending orders
            // reset openPrice
            cancelAll()
            openPrice = 0
        }
        Sleep(1000)
    }
}

Parâmetros da estratégia:

img

Oh sim! A estratégia precisa de um nome, vamos chamá-lo de adivinhar o tamanho (versão dYdX) .

Teste de retrocesso

O backtesting é apenas para referência, >_

img

img

img

img

O backtest terminou, não há bug.

Esta estratégia é usada apenas para aprendizagem e referência, não a use no bot real!


Relacionados

Mais.