Novato, confira Leva-o ao Comércio Quantitativo de Criptomoedas (5)

Autora:Ninabadass, Criado: 2022-04-18 17:20:53, Atualizado: 2022-04-18 17:30:27

Novato, confira Leva-o ao Comércio Quantitativo de Criptomoedas (5)

No último artigo, explicamos a análise lógica de negociação de uma estratégia de grade simples.

  • Análise da lógica de negociação Como mencionamos no artigo anterior, desde que você atravesse cada linha da grade da grade e julgue que o preço atual cruza a linha da grade para cima ou para baixo, a ação de negociação pode ser acionada.

    O primeiro detalhe que temos que considerar é o projeto da grade infinita.createNetEsta função gera uma estrutura de dados de rede com um número finito de linhas de rede. Então, e se, quando a estratégia está em execução, o preço ultrapassa os limites desta estrutura de dados de rede (além da linha de rede superior onde o preço é o mais alto, e a linha de rede inferior onde o preço é o mais baixo)? Então, primeiro precisamos adicionar um mecanismo de extensão à estrutura de dados da grade.

    Comece a escrever a função principal da estratégia, e a função principal é o código onde a estratégia começa a ser executada.

    var diff = 50                                 // global variable, the grid interval, can be designed as parameter; for an easy explanation, we write it in an infinite loop 
    function main() {
        // After the bot starts running, execute the strategy code from here
        var ticker = _C(exchange.GetTicker)       // obtain the latest ticker data in the market; for the ticker data structure, you can refer to FMZ API documentation: https://www.fmz.com/api#ticker
        var net = createNet(ticker.Last, diff)    // the function to initially construct the grid data structure we designed in the previous article; here we construct a grid data structure net
    
        while (true) {                            // then, the program logic enters the while infinite loop, and the strategy will repeatedly execute the code within the {} symbol from here
            ticker = _C(exchange.GetTicker)       // the first line of the infinite loop code gets the latest market quote data, and updates it to the variable ticker 
            // check the grid range 
            while (ticker.Last >= net[net.length - 1].price) {
                net.push({
                    buy : false,
                    sell : false,
                    price : net[net.length - 1].price + diff,
                })
            }
            while (ticker.Last <= net[0].price) {
                var price = net[0].price - diff
                if (price <= 0) {
                    break
                }
                net.unshift({
                    buy : false,
                    sell : false,
                    price : price,
                })
            }
            
            // the code is not completed...
        }
    }
    

    É o código que torna a estrutura de dados da grade extensivel (extraído do código acima):

          // check the grid range 
          while (ticker.Last >= net[net.length - 1].price) {   // if the price exceeds the grid line with the highest price in the grid,
              net.push({                                       // add a new grid line after the grid line with the highest price in the grid
                  buy : false,                                 // initialize the sell mark 
                  sell : false,                                // initialize the buy mark 
                  price : net[net.length - 1].price + diff,    // add a grid interval on the basis of the previous highest price
              })
          }
          while (ticker.Last <= net[0].price) {                // if the price is lower than the grid line with the lowest price in the grid,
              var price = net[0].price - diff                  // distinguished from adding upwards, you should notice the price of the newly added grid line downwards cannot be less than or equal to 0, so you need to judge here 
              if (price <= 0) {                                // do not add when the price is less than or equal to 0, and break the loop 
                  break
              }
              net.unshift({                                    // add a new grid line before the grid line with the lowest price in the grid 
                  buy : false,
                  sell : false,
                  price : price,
              })
          }
    

    Em seguida, precisamos considerar como implementar o gatilho de negociação.

    var diff = 50
    var amount = 0.002       // add a global variable, which can also be designed as a parameter; for easy explanation, we can write it in an infinite loop 
                             // the parameter controls the trading amount on the grid line each time the trading is triggered 
    function main() {
        var ticker = _C(exchange.GetTicker)
        var net = createNet(ticker.Last, diff)
        var preTicker = ticker       // before the start of the main (infinite) loop, set a variable, to record the market quotes of last time 
        while (true) {
            ticker = _C(exchange.GetTicker)
            // check the grid range 
            while (ticker.Last >= net[net.length - 1].price) {
                net.push({
                    buy : false,
                    sell : false,
                    price : net[net.length - 1].price + diff,
                })
            }
            while (ticker.Last <= net[0].price) {
                var price = net[0].price - diff
                if (price <= 0) {
                    break
                }
                net.unshift({
                    buy : false,
                    sell : false,
                    price : price,
                })
            }  
    
            // index the grid 
            for (var i = 0 ; i < net.length ; i++) {     // traverse all grid lines in the grid data structure 
                var p = net[i]
                if (preTicker.Last < p.price && ticker.Last > p.price) {         // upcross, and sell; when the current node has been traded, no matter SELL or BUY, no more trade
                    if (i != 0) {
                        var downP = net[i - 1]
                        if (downP.buy) {
                            exchange.Sell(-1, amount, ticker)
                            downP.buy = false 
                            p.sell = false 
                            continue
                        }
                    }
                    if (!p.sell && !p.buy) {
                        exchange.Sell(-1, amount, ticker)
                        p.sell = true
                    }
                } else if (preTicker.Last > p.price && ticker.Last < p.price) {  // downcross, and buy 
                    if (i != net.length - 1) {
                        var upP = net[i + 1]
                        if (upP.sell) {
                            exchange.Buy(-1, amount * ticker.Last, ticker)
                            upP.sell = false 
                            p.buy = false 
                            continue
                        }
                    }
                    if (!p.buy && !p.sell) {
                        exchange.Buy(-1, amount * ticker.Last, ticker)
                        p.buy = true 
                    } 
                }
            }
            preTicker = ticker    // record the current market quotes in preTicker, which will be used as the "last" market quote data to compare with the new one in next loop, to judge upcross and downcross 
            Sleep(500)
        }
    }  
    

    Podem ver:

    • Condição de cruzamento da linha de rede:preTicker.Last < p.price && ticker.Last > p.price
    • Condição de cruzamento da linha da rede:preTicker.Last > p.price && ticker.Last < p.price

    Foi sobre isto que falámos no último artigo:

    img

    Julgar upcross ou downcross é apenas o primeiro passo para determinar se se deve encomendar e negociar, e a marca nos dados da linha da grade também precisa ser julgada.

    Se for upcross, então julgue se o preço é menor do que a linha da grade atual, bem como a marca de compra na linha da grade mais recente; se o valor da marca de compra for verdadeiro, isso significa que a última linha da grade executada comprou e redefiniu a marca de compra da última linha da grade como falsa e redefiniu a marca de venda da linha da grade atual como falsa.

    Depois de julgar as condições mencionadas agora, se elas não são desencadeadas, a continuar a julgar. Se a marca de compra e marca de venda da linha de rede atual são ambos falsos, isso significa que a linha de rede atual pode negociar; para ele é upcross, aqui executamos operação de venda, e marcar a marca de venda da linha de rede como verdadeiro após a execução.

    A lógica de processamento do downcross é a mesma. (novatos podem pensar sobre isso por si mesmos.)

Teste de retrocesso da estratégia completa

A fim de ver alguns dados durante backtest, uma funçãoshowTblé escrito para exibir os dados.

function showTbl(arr) {
    var tbl = {
        type : "table", 
        title : "grid",
        cols : ["grid information"],
        rows : []
    }
    var arrReverse = arr.slice(0).reverse()
    _.each(arrReverse, function(ele) {
        var color = ""
        if (ele.buy) {
            color = "#FF0000"
        } else if (ele.sell) {
            color = "#00FF00"
        }
        tbl.rows.push([JSON.stringify(ele) + color])
    })
    LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n account information:", exchange.GetAccount())
}

Código completo da estratégia:

/*backtest
start: 2021-04-01 22:00:00
end: 2021-05-22 00:00:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"OKEX","currency":"ETH_USDT","balance":100000}]
*/

var diff = 50
var amount = 0.002
function createNet(begin, diff) {
    var oneSideNums = 10
    var up = []
    var down = []
    for (var i = 0 ; i < oneSideNums ; i++) {
        var upObj = {
            buy : false,
            sell : false, 
            price : begin + diff / 2 + i * diff,
        }
        up.push(upObj)

        var j = (oneSideNums - 1) - i
        var downObj = {
            buy : false,
            sell : false,
            price : begin - diff / 2 - j * diff,
        }
        if (downObj.price <= 0) {  // the price cannot be less than or equal to 0 
            continue
        }
        down.push(downObj)
    }

    return down.concat(up)
}

function showTbl(arr) {
    var tbl = {
        type : "table", 
        title : "grid",
        cols : ["grid information"],
        rows : []
    }
    var arrReverse = arr.slice(0).reverse()
    _.each(arrReverse, function(ele) {
        var color = ""
        if (ele.buy) {
            color = "#FF0000"
        } else if (ele.sell) {
            color = "#00FF00"
        }
        tbl.rows.push([JSON.stringify(ele) + color])
    })
    LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n account information:", exchange.GetAccount())
}

function main() {
    var ticker = _C(exchange.GetTicker)
    var net = createNet(ticker.Last, diff)
    var preTicker = ticker 
    while (true) {
        ticker = _C(exchange.GetTicker)
        // check the grid range 
        while (ticker.Last >= net[net.length - 1].price) {
            net.push({
                buy : false,
                sell : false,
                price : net[net.length - 1].price + diff,
            })
        }
        while (ticker.Last <= net[0].price) {
            var price = net[0].price - diff
            if (price <= 0) {
                break
            }
            net.unshift({
                buy : false,
                sell : false,
                price : price,
            })
        }

        // index grid 
        for (var i = 0 ; i < net.length ; i++) {
            var p = net[i]
            if (preTicker.Last < p.price && ticker.Last > p.price) {         // upcross, and sell; when the current node has been traded, no matter SELL or BUY, no more trade
                if (i != 0) {
                    var downP = net[i - 1]
                    if (downP.buy) {
                        exchange.Sell(-1, amount, ticker)
                        downP.buy = false 
                        p.sell = false 
                        continue
                    }
                }
                if (!p.sell && !p.buy) {
                    exchange.Sell(-1, amount, ticker)
                    p.sell = true
                }
            } else if (preTicker.Last > p.price && ticker.Last < p.price) {  // downcross, and buy 
                if (i != net.length - 1) {
                    var upP = net[i + 1]
                    if (upP.sell) {
                        exchange.Buy(-1, amount * ticker.Last, ticker)
                        upP.sell = false 
                        p.buy = false 
                        continue
                    }
                }
                if (!p.buy && !p.sell) {
                    exchange.Buy(-1, amount * ticker.Last, ticker)
                    p.buy = true 
                } 
            }
        }

        showTbl(net)
        preTicker = ticker 
        Sleep(500)
    }
}

Estratégia Backtest:

img

img

img

Podem ver as características da estratégia de rede. Quando há um mercado em tendência, haverá uma grande perda flutuante, e o retorno vai se recuperar em um mercado volátil. Por conseguinte, a estratégia de rede não é isenta de risco. A estratégia spot ainda pode manter-se para torná-la igual, enquanto a estratégia de rede de contratos futuros é mais arriscada e precisa definir os parâmetros da rede de forma conservadora.


Mais.