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, projetamos várias estratégias sincronizadas de ordem e posição.

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).

img

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):

img

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)
    }
}

img

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.