Design de um sistema de gerenciamento de pedidos sincronizados baseado em FMZ

Autora:Sonhos pequenos, Criado: 2022-02-14 19:46:30, Atualizado: 2023-09-15 20:44:11

img

Design de um sistema de gerenciamento de pedidos sincronizados baseado em FMZ

Em artigos anteriores da base de dados da FMZ, desenvolvemos várias estratégias de sincronização de pedidos e armazenamento.

Estas são as contas de referência e as contas de sincronização em uma única estratégia para gerenciar a implementação de ordens, sincronização de estoque. Hoje vamos experimentar um design um pouco diferente, baseado na interface API de extensão poderosa da plataforma de negociação quantitativa FMZ, e vamos projetar um sistema de gerenciamento de sincronização de ordens.

Ideias de Design

Para começar, precisamos de algumas boas sugestões, necessidades.

  • Os implementadores de estratégias de sincronização em disco real devem ter o API KEY da bolsa de contas de referência. O problema para o cenário de uso é que: é bom que as próprias contas de outras casas de câmbio sigam a sua própria conta; mas pode ser um problema para as contas de referência e as contas sincronizadas que não são do mesmo proprietário. Os proprietários de contas sincronizadas, por vezes, por razões de segurança, não querem fornecer a API KEY de suas próprias contas de câmbio; mas como sincronizar uma transação sem fornecer a API KEY?

    A solução: Usando a API de extensão do FMZ, os proprietários de contas de sincronização (os assinantes) só precisam se registrar no FMZ Quantum Trading Platform e executar uma política (no sistema projetado para este artigo):订单同步管理系统(Synchronous Server)A política de disco rígido) ; em seguida, pode-se fornecer o ID do disco rígido do sistema de gestão de ordens sincronizadas ("Synchronous Server") para o proprietário da conta de referência ("Band") com o API KEY da extensão FMZ (nota, não o API KEY da conta da bolsa). Quando o disco físico do titular da conta de referência (bandido) no sistema concebido para este artigo订单同步管理系统类库(Single Server)O proprietário da conta de sincronização recebe um sinal de transação no seu computador, que é automaticamente transferido para o seu computador.

  • 2, muitos desenvolvedores têm estratégias comparativas e não podem usar as duas ordens de prazo descritas acima, a estratégia de sincronização de estoque. Isso requer a integração de suas estratégias com essas estratégias de sincronização, que podem exigir grandes mudanças e esforço. Há uma boa maneira de melhorar diretamente as suas estratégias de sincronização de ordens? A solução: É possível criar uma biblioteca de modelos de sincronização de pedidos (em um sistema projetado para este artigo)订单同步管理系统类库(Single Server)A ferramenta é usada para executar o processo de seleção de um modelo de modelo de modelo de modelo de modelo de modelo.

  • 3⁄4 Redução de um disco real extra. O último ponto negativo é que, se você usar as duas ordens para futuros descritas acima, a estratégia de sincronização de estoque será necessária para abrir uma conta de referência de monitoramento de estoque em tempo real. A solução: Utilize a biblioteca de modelos para incorporar funções na política de contas de referência.

O sistema é composto por duas partes: 1, Sistema de gestão de sincronização de pedidos (Single Server) Sistema de gestão de encomendas sincronizadas (Synchronous Server)

Se você tiver uma ideia do que você precisa, comece a projetar!

Design 1: Sistema de gestão de sincronização de pedidos (Single Server)

Observe que esta não é uma estratégia; é uma biblioteca de modelos para FMZ, e o conceito de biblioteca de modelos pode ser pesquisado no documento da API FMZ, que não é mais descrito aqui.

Código da biblioteca de modelos:

// 全局变量
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) {
        // 开仓
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // 发送信号
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // 平仓
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("未检测到持仓")
            return 
        }
        // 发送信号
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)
    } else {
        throw "错误"
    }
    if (msg) {
        _.each(fmzExtendApis, function(extendApiConfig) {
            var ret = sendCommandRobotMsg(extendApiConfig[keyName_robotId], extendApiConfig[keyName_extendAccessKey], extendApiConfig[keyName_extendSecretKey], msg)
            Log("调用CommandRobot接口,", "label:", extendApiConfig[keyName_label], ", msg:", msg, ", ret:", ret)
            Sleep(1000)
        })
    }
}

$.PosMonitor = function(exIndex, symbol, ct) {    
    var ts = new Date().getTime()
    var ex = exchanges[exIndex]
    // 判断ex类型
    var exName = ex.GetName()
    var isFutures = exName.includes("Futures_")
    var exType = isFutures ? "futures" : "spot"
    if (!isFutures) {
        throw "仅支持期货跟单"
    }

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

        // 切换到对应的交易对、合约代码
        ex.SetCurrency(symbol)
        if (!ex.SetContractType(ct)) {
            throw "SetContractType failed"
        }

        // 监控持仓
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // 没有初始化数据,初始化          
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

        // 监控
        var nowRefPosAmount = getPosAmount(_C(ex.GetPosition), ct)
        // 计算仓位变动
        var longPosDelta = nowRefPosAmount.long - initRefPosAmount.long
        var shortPosDelta = nowRefPosAmount.short - initRefPosAmount.short

        // 检测变动
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // 执行多头动作
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行多头跟单,变动量:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // 执行空头动作
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "执行空头跟单,变动量:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // 执行跟单操作后,更新
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

        // 恢复 symbol ct
        ex.SetCurrency(buffSymbol)
        ex.SetContractType(buffCt)
    } else if (exType == "spot") {
        // 现货
    }
}

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "同步数据", 
        "cols" : [], 
        "rows" : []
    }
    // 构造表头
    tbl.cols.push("监控账户:refPos-exIndex-symbol-contractType")
    tbl.cols.push(`监控持仓:{"时间戳":xxx,"多头持仓量":xxx,"空头持仓量":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // 写入数据
    _.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
}

// 引用该模板类库的策略调用范例
function main() {
    // 清除所有日志
    LogReset(1)

    // 切换到OKEX 模拟盘测试
    exchanges[0].IO("simulate", true)

    // 设置合约
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // 定时交易时间间隔
    var tradeInterval = 1000 * 60 * 3        // 三分钟交易一次,用于观察跟单信号
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // 策略其它逻辑...

        // 用于测试的模拟交易触发
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("模拟带单策略发生交易,持仓变化", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // 使用模板的接口函数
        $.PosMonitor(0, "ETH_USDT", "swap")    // 可以设置多个监控,监控带单策略上的不同的exchange对象  
        var tbl = $.getTbl()
        
        // 显示状态栏
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

O projeto é muito simples e a biblioteca tem duas funções.订单同步管理系统类库(Single Server)Após a biblioteca de classes de modelo. Esta política pode ser usada com a seguinte função.

  • $ PosMonitor O papel da função é monitorar as mudanças de posicionamento dos objetos da troca na política e enviar sinais de negociação para o disco real definido nos parâmetros do modelo: Orders Synchronous Management System Library ("Single Server").

  • $$. getTbl O Google Analytics é uma ferramenta de pesquisa de dados que fornece informações sobre o sistema de monitoramento.

Exemplos de uso são: O modelo de um sistema de gestão de sincronização de pedidos (Single Server)mainA função:

// 引用该模板类库的策略调用范例
function main() {
    // 清除所有日志
    LogReset(1)

    // 切换到OKEX 模拟盘测试
    exchanges[0].IO("simulate", true)

    // 设置合约
    exchanges[0].SetCurrency("ETH_USDT")
    exchanges[0].SetContractType("swap")

    // 定时交易时间间隔
    var tradeInterval = 1000 * 60 * 3        // 三分钟交易一次,用于观察跟单信号
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // 策略其它逻辑...

        // 用于测试的模拟交易触发
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("模拟带单策略发生交易,持仓变化", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // 使用模板的接口函数
        $.PosMonitor(0, "ETH_USDT", "swap")    // 可以设置多个监控,监控带单策略上的不同的exchange对象  
        var tbl = $.getTbl()
        
        // 显示状态栏
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Uma biblioteca de tipos de modelos pode também criar o próprio disco rígido de políticas, normalmente usado para testar a biblioteca de tipos de modelos.mainA função é a sua própria estratégia.mainFunção.

O código do teste foi escrito para testar usando o disco OKEX, que requer a configuração do API KEY do disco OKEX no FMZ como uma conta de referência (banda), para iniciar a comutação no disco em uma função principal. Em seguida, configure o par de transações para ETH_USDT e configure o contrato para permanente (swap). Em seguida, entre em um ciclo de enquanto.$.PosMonitor(0, "ETH_USDT", "swap")O primeiro parâmetro a ser chamado é 0, que significa monitorar exchanges[0] que monitoram a troca de ETH_USDT e os contratos de swap.$.getTbl()Obtenção de informações gráficas, usoLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")Faça com que os dados do gráfico apareçam na barra de status.

Então, você vê, basta usar uma estratégia que se refere ao modelo.$.PosMonitor(0, "ETH_USDT", "swap")A estratégia pode ter funções de monitoramento de uma variedade de posicionamento, de mudança de posicionamento para enviar mensagens.

Explique antes do teste.订单同步管理系统类库(Single Server)O design dos parâmetros da estratégia: Afinal, o que é um sinal de mudança de posição, para quem é enviado? A questão de a quem enviar é feita por:订单同步管理系统类库(Single Server)Os parâmetros do sistema são configurados.

img

Pode-se ver que há 5 parâmetros, com um máximo de 5 suporte de empurrões (se necessário, adicionar pode ser expandido), o parâmetro por padrão é uma string vazia, ou seja, não é processado.

  • etiqueta As etiquetas de contas sincronizadas são usadas para marcar uma conta e o nome pode ser configurado como quiser.

  • RobotId ID de disco físico, criado pelo proprietário da conta de sincronização订单同步管理系统(Synchronous Server)O ID do disco real.

  • AccessKey AccessKey para a extensão da API do FMZ

  • SecretKey SecretKey para a extensão da API do FMZ

A partir daí, podemos fazer um teste simples.

O sistema de gestão de sincronização de pedidos (Single Server) é executado:

img

O disco rígido do sistema de gestão de encomendas (Synchronous Server) recebeu um sinal: O sistema de gerenciamento de pedidos sincronizado (Synchronous Server) ainda não foi projetado, mas foi implementado com um código simples, sem transações, apenas imprimindo sinais:

Sistema de Gestão de Encomendas Sincronizado (Synchronous Server) código temporário:

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

img

A mensagem foi enviada para o disquete do proprietário da conta de sincronização:ETH_USDT,swap,buy,1Não, não é. Assim, o próximo passo é fazer o seu próprio cronograma automático com base nos pares de transações, códigos de contrato, direção de negociação e quantidade de transações na informação.

Atualmente订单同步管理系统(Synchronous Server)O código é apenas temporário, mas vamos continuar a explorar o design em nosso próximo artigo.


Relacionados

Mais.

Mingxi1005Para implementar a listagem, ainda é necessário dois discos, um disco de classe e um disco do sistema de gestão de pedidos.

Mingxi1005Aconteceu o tutorial, mostrando um erro de configuração

AlegriaOs parâmetros que precisam ser alterados na lista de conversão

AlegriaSe você quer fazer isso, você precisa abrir dois discos, um para transmitir e outro para receber, e os dois discos podem ser combinados?

Sonhos pequenosSe você não entendeu o artigo, esta biblioteca de classes é uma ferramenta que pode ser incorporada diretamente na linha de políticas do usuário e, em seguida, a política tem função de faixa e envia mensagens para as contas de conta configuradas, e o bot recebe mensagens de conta. A situação é simplesmente essa.

Sonhos pequenosVocê pode ver o artigo, informações de configuração: etiqueta, ID de disco real, accesskey, secretkey.

Mingxi1005O erro configs error!, no banco de dados do sistema de gestão de sincronização de pedidos (Single Server), preencheu o disco do cliente e os dois KEYs, e depois o banco de dados referiu-se ao banco de dados do sistema de gestão de sincronização de pedidos (Single Server), o que gerou um erro, o erro configs error!

Mingxi1005Erro de configuração!

Sonhos pequenosO que é que é um erro de informação?

Sonhos pequenosA política precisa ser alterada.

Sonhos pequenosO código é aberto e você pode alterá-lo conforme sua necessidade.