Projeto do sistema de gestão síncrona baseado em ordens FMZ (1)

Autora:Ninabadass, Criado: 2022-04-06 15:08:26, Atualizado: 2022-04-24 18:00:51

Projeto do sistema de gestão síncrona baseado em ordens FMZ (1)

Nos artigos anteriores no FMZ Digest, nós concebemos várias estratégias sincronizadas de ordem e posição. - Não.Realizar um bot simples de supervisão de ordens spot de criptomoedas - Ordem Simples Supervisando Bot do Contrato de Criptomoeda

Esses projetos levam a conta de referência e a conta síncrona na mesma estratégia para ser gerenciada para realizar a sincronização de ordens e posições.

Pensamento por Design

Em primeiro lugar, precisamos de algumas boas sugestões e requisitos. As duas estratégias de sincronização de ordens e posições anteriores acima têm várias desvantagens óbvias.

  • 1.Os utilizadores que implementam a sincronização de estratégias de bots devem dispor da API KEY da plataforma de conta de referência e da API KEY da conta de sincronização. Para o cenário de uso, o problema é: é bom que suas outras contas da plataforma sigam uma de suas próprias contas. Mas pode ser problemático para o cenário em que a conta de referência e a conta de sincronização não têm o mesmo proprietário. O proprietário da conta de sincronização às vezes não está disposto a fornecer a API KEY de sua conta da plataforma devido a considerações de segurança. Mas como colocar uma ordem para negociação sincronizada sem fornecer a API KEY?

Solução: Usando a API estendida FMZ, o proprietário da conta de sincronização (o supervisor de ordens) só precisa registrar a plataforma de negociação FMZ Quant e, em seguida, executar uma estratégia (no sistema projetado neste artigo:Order Synchronous Management System (Synchronous Server)Em seguida, a chave API estendida do FMZ (observe que não é a chave API da conta da plataforma) e o ID do bot do sistema de gerenciamento de sincronização de ordens (Synchronous Server) serão fornecidos ao proprietário da conta de referência (o proprietário da ordem). Quando o bot do titular da conta de referência (o titular da ordem) (Order Synchronous Management System Library (Single Server)O bot do proprietário da conta de sincronização receberá o sinal de negociação e a ordem será colocada automaticamente mais tarde.

  • 2.Muitos desenvolvedores têm melhores estratégias e não podem usar as duas estratégias anteriores de sincronização de ordem e posição descritas acima. Porque isso precisa mesclar suas próprias estratégias com essas estratégias de sincronização, e suas estratégias podem precisar ser muito modificadas, o que é demorado e trabalhoso. Há uma boa maneira de atualizar diretamente algumas de suas estratégias maduras para aquelas com a função de sincronização de ordem?

Solução: Você pode projetar uma biblioteca de modelos sincronizados de ordem (oOrder Synchronous Management System Library (Single Server)A estratégia de referência é uma estratégia de referência (ou seja, uma estratégia de referência no sistema concebido no artigo), de modo que o proprietário da conta de referência (o proprietário da encomenda) possa inserir directamente esta biblioteca de modelos na sua própria estratégia para alcançar a sincronização de ordem e posição.

  • 3.Reduzir um bot extra A última desvantagem é que, se você usar as duas ordens anteriores e as estratégias de sincronização de posição descritas acima, é necessário abrir uma posição adicional da conta de referência (conta com ordens) para monitoramento de bots. Solução: Use a biblioteca de modelos para incorporar a função na estratégia de conta de referência.

Por conseguinte, o sistema consiste em duas partes: 1.Biblioteca do sistema de gestão sincronizada de ordens (servidor único) 2.Sistema de gestão síncrona de encomendas (Servidor síncrono)

Uma vez que tenhamos certeza das nossas exigências, vamos começar a desenhar!

Projeto 1: Biblioteca de Sistemas de Gestão Síncrona de Ordem (Servidor Único)

Preste atenção que aqui não é uma estratégia, mas uma biblioteca de modelos FMZ, que pode ser pesquisado na documentação FMZ API e não vamos discutir aqui.

Código do modelo:

// Global variable
var keyName_label = "label"
var keyName_robotId = "robotId"
var keyName_extendAccessKey = "extendAccessKey"
var keyName_extendSecretKey = "extendSecretKey"
var fmzExtendApis = parseConfigs([config1, config2, config3, config4, config5])
var mapInitRefPosAmount = {}

function parseConfigs(configs) {
    var arr = []
    _.each(configs, function(config) {
        if (config == "") {
            return 
        }
        var strArr = config.split(",")
        if (strArr.length != 4) {
            throw "configs error!"
        }
        var obj = {}
        obj[keyName_label] = strArr[0]
        obj[keyName_robotId] = strArr[1]
        obj[keyName_extendAccessKey] = strArr[2]
        obj[keyName_extendSecretKey] = strArr[3]
        arr.push(obj)
    })
    return arr 
}

function getPosAmount(pos, ct) {
    var longPosAmount = 0
    var shortPosAmount = 0
    _.each(pos, function(ele) {
        if (ele.ContractType == ct && ele.Type == PD_LONG) {
            longPosAmount = ele.Amount
        } else if (ele.ContractType == ct && ele.Type == PD_SHORT) {
            shortPosAmount = ele.Amount
        }
    })
    var timestamp = new Date().getTime()
    return {ts: timestamp, long: longPosAmount, short: shortPosAmount}
}

function sendCommandRobotMsg (robotId, accessKey, secretKey, msg) {
    // https://www.fmz.com/api/v1?access_key=xxx&secret_key=yyyy&method=CommandRobot&args=[186515,"ok12345"]
    var url = "https://www.fmz.com/api/v1?access_key=" + accessKey + "&secret_key=" + secretKey + "&method=CommandRobot&args=[" + robotId + ',"' + msg + '"]'
    Log(url)
    var ret = HttpQuery(url)
    return ret 
}

function follow(nowPosAmount, symbol, ct, type, delta) {
    var msg = ""
    var nowAmount = type == PD_LONG ? nowPosAmount.long : nowPosAmount.short
    if (delta > 0) {
        // Open position
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // Send signal
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // Open position 
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("No position detected")
            return 
        }
        // Send signal 
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
    } else {
        throw "error"
    }
    if (msg) {
        _.each(fmzExtendApis, function(extendApiConfig) {
            var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
            Log("Call CommandRobot interface,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
            Sleep(1000)
        })
    }
}

$.PosMonitor = function(exIndex, symbol, ct) {    
    var ts = new Date().getTime()
    var ex = exchanges[exIndex]
    // Judge the type of ex
    var exName = ex.GetName()
    var isFutures = exName.includes("Futures_")
    var exType = isFutures ? "futures" : "spot"
    if (!isFutures) {
        throw "Only support futures order supervising"
    }

    if (exType == "futures") {
        // Cache symbol ct
        var buffSymbol = ex.GetCurrency()
        var buffCt = ex.GetContractType()

        // Switch to the corresponding trading pair and contract code 
        ex.SetCurrency(symbol)
        if (!ex.SetContractType(ct)) {
            throw "SetContractType failed"
        }

        // Monitor position 
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // The data is not initialized; initialize it          
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

        // Monitor
        var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
        // Calculate position changes 
        var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
        var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short

        // Detect changes 
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // Execute long position action 
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Execute long position order supervision, change volume:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // Execute short position action 
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Execute short position order supervision, change volume:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // After executing the order supervision operation, update  
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

        // Recover symbol ct
        ex.SetCurrency(buffSymbol)
        ex.SetContractType(buffCt)
    } else if (exType == "spot") {
        // Spot 
    }
}

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "Synchrodata", 
        "cols" : [], 
        "rows" : []
    }
    // Construct the table title 
    tbl.cols.push("Monitoring account:refPos-exIndex-symbol-contractType")
    tbl.cols.push(`Mintoring position:{"timestamp":xxx,"long position volume":xxx,"short position volume":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // Write in the data 
    _.each(mapInitRefPosAmount, function(initRefPosAmount, key) {
        var arr = [key, JSON.stringify(initRefPosAmount)]
        _.each(fmzExtendApis, function(extendApiData) {
            arr.push(extendApiData[keyName_robotId])
        })
        tbl.rows.push(arr)
    })

    return tbl
}

// Invocation example of the strategy in the template
function main() {
    // Clear all logs
    LogReset(1)

    //Switch to OKEX simulated bot test
    exchanges[0].IO("simulate", true)

    // Set contract 
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // Timed trading time interval
    var tradeInterval = 1000 * 60 * 3        // trade every three minutes, to observe the order supervising signal  
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strategy...

        // Used to test the simulated trade trigger  
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Simulated strategy with orders has trades, and positions changed", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Call the interface function in the template 
        $.PosMonitor(0, "ETH_USDT", "swap")    // You can set multiple monitors, to minitor different exchange objects in the strategy with orders
        var tbl = $.getTbl()
        
        // Display the status bar 
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

O projeto é muito simples, a biblioteca tem 2 funções.Order Synchronous Management System Library (Single Server)Esta estratégia pode então usar as seguintes funções.

  • $. Post-Monitor O efeito desta função é monitorizar as alterações de posição dos objetos de troca na estratégia e, em seguida, enviar sinais de negociação para o bot definido nos parâmetros do modelo: ordem biblioteca de sistema de gestão síncrona (Single Server).
  • $. GetTbl A função devolve os dados síncronos monitorizados.

O exemplo de utilização está nomainFunção na biblioteca do sistema de gestão síncrona de ordens (servidor único):

// Invocation example of the strategy in the template 
function main() {
    // Clear all logs 
    LogReset(1)

    // Switch to OKEX simulated bot test 
    exchanges[0].IO("simulate", true)

    // Set contract 
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // Timed trading time interval
    var tradeInterval = 1000 * 60 * 3        // trade every three minutes, to observe the order supervising signal  
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strateg...

        // Used to test the simulated trade trigger  
        var ts = new Date().getTime()
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Simulated strategy with orders has trades, and positions changed", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Use the interface function of the template 
        $.PosMonitor(0, "ETH_USDT", "swap")    // You can set multiple monitors to monitor different exchange objects on an strategy with orders
        var tbl = $.getTbl()
        
        // Display the status bar
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Uma biblioteca de modelos em si também pode criar um bot de estratégia, que é geralmente usado para testar a biblioteca de modelos.mainA função no modelo é amainA função de uma das suas estratégias.

O código de teste é escrito para usar o bot simulado OKEX para testar, e a chave API do bot simulado OKEX precisa ser configurada no FMZ como uma conta de referência (com ordens), e a função principal começa a mudar para o bot simulado. Em seguida, defina o par de negociação para ETH_USDT e defina o contrato para swap. Em seguida, insira um loop while. No loop, uma ordem é colocada a cada 3 minutos para simular o gatilho das negociações de estratégia.$.PosMonitor(0, "ETH_USDT", "swap")é chamado no loop enquanto, e o primeiro parâmetro da função chamada é 0, o que significa monitorar as trocas de objeto de troca[0], o par de negociação ETH_USDT, e contrato de swap.$.getTbl()para obter as informações do gráfico, e usarLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")para fazer com que os dados do gráfico sejam exibidos na barra de estado.

Então, como vês, desde que$.PosMonitor(0, "ETH_USDT", "swap")Se o símbolo é utilizado numa estratégia que chama o modelo, a estratégia pode ter a função de monitorizar uma determinada posição do símbolo e enviar a mensagem de alteração de posição.

Antes do ensaio, explicar o desenho dos parâmetros doOrder Synchronous Management System Library (Single Server)Estratégia: Eu acabei de falar sobre como usar a função de interface do modelo para fazer uma atualização de estratégia com uma função de realizar ordens. A questão de a quem enviar é configurada pelos parâmetros deorder synchronous management system library (Single Server).

FMZ Based Order Synchronous Management System Design (1)

Você pode ver cinco parâmetros, que podem suportar no máximo cinco pushes (se você precisa aumentar o número de pushes, você pode estendê-lo por si mesmo); o padrão dos parâmetros é uma cadeia vazia, ou seja, não processada.

  • etiqueta O rótulo da conta síncrona, utilizado para rótulo de uma conta; o nome da etiqueta pode ser definido aleatoriamente.

  • robotId O bot ID; o bot ID doorder synchronous management system (Synchronous Server)Criado pelo proprietário da conta sincronizada.

  • acessoKey A AccessKey da FMZ estendeu a API.

  • chave secreta A chave secreta da FMZ estendeu a API.

Depois, podemos fazer um teste simples.

Operação de bot da biblioteca do sistema de gestão síncrono (servidor único):

FMZ Based Order Synchronous Management System Design (1)

O bot do Sistema de Gestão Sincronizado de Ordens (Servidor Sincronizado) recebeu o sinal: Ordem Sistema de Gerenciamento Sincrônico (Synchronous Server) agora não foi completamente projetado por nós, e podemos usar um código simples para realizá-lo, sem negociação, apenas impressão de sinal:

Código temporário do sistema de gestão síncrono de encomendas (servidor síncrono):

function main() {
    LogReset(1)
    while (true) {
        var cmd = GetCommand()
        if (cmd) {
            // cmd: ETH_USDT,swap,buy,1
            Log("cmd: ", cmd)
        }
        Sleep(1000)
    }
}

FMZ Based Order Synchronous Management System Design (1)

Como podem ver, o bot do proprietário da conta sincronizada recebeu a mensagem:ETH_USDT,swap,buy,1- Não. Assim, na próxima etapa, podemos supervisionar ordens automaticamente, de acordo com o par de negociação, código do contrato, direção de negociação e volume.

Atualmente,order synchronous management system (Synchronous Server)é apenas um código temporário, e podemos discutir mais sobre o seu design no próximo artigo.


Mais informações