Diseño de un sistema de gestión de sincronización de pedidos basado en FMZ Quant (1)

El autor:- ¿ Por qué?, Creado: 2022-11-07 10:20:01, Actualizado: 2023-09-15 20:45:23

img

Diseño de un sistema de gestión de sincronización de pedidos basado en FMZ Quant (1)

En artículos anteriores en la biblioteca FMZs, hemos diseñado varios tipos de estrategias de sincronización para el orden y la posición.

Estas gestionan las cuentas de referencia y las cuentas sincronizadas en una estrategia para lograr la sincronización de orden y posición. y hoy vamos a probar un diseño diferente, vamos a diseñar un sistema de gestión de sincronización de pedidos basado en la potente interfaz API extendida de la plataforma de comercio de FMZ Quant.

Ideas de diseño

En primer lugar, necesitamos algunas buenas sugerencias y necesidades. Las dos estrategias anteriores de sincronización de orden y posición, que tienen varias deficiencias obvias, que discutiremos juntos.

    1. Los usuarios de estrategias de sincronización real bot deben tener el intercambio API KEY de la cuenta de referencia, y el intercambio API KEY de la cuenta de sincronización. Este problema está bien para la situación de uso en la que las otras cuentas de intercambio de uno siguen su propia cuenta. Sin embargo, puede ser problemático para la situación en la que la cuenta de referencia y la cuenta de sincronización no son el mismo propietario. A veces, el propietario de la cuenta sincronizada no quiere proporcionar la clave API de su propia cuenta de intercambio por razones de seguridad, pero ¿cómo sincronizar las transacciones de pedido sin proporcionar la clave API?

    Soluciones: Utilice la interfaz API extendida de FMZ, el propietario de la cuenta sincronizada (seguidor de pedidos) solo necesita registrar una cuenta en la plataforma de negociación de FMZ Quant, luego ejecute una estrategia (en el sistema diseñado en este artículo:Order Synchronous ServerEstrategia en Real Bot). A continuación, simplemente proporcione la clave API extendida FMZ (tenga en cuenta que no es la clave API de la cuenta de intercambio) y el ID de bot real del servidor de orden sincrónico al propietario de la cuenta de referencia (líder de orden). Cuando el propietario de la cuenta de referencia (seguidores de la orden) es un bot real (elOrder Synchronization Management System Class Library (Single Server)En el sistema diseñado en este artículo) envía una señal, el bot real del propietario de la cuenta de sincronización recibirá la señal de negociación y realizará el pedido posterior automáticamente.

    1. Muchos desarrolladores tienen buenas estrategias, pero no pueden usar las 2 estrategias de sincronización de orden y posición anteriores descritas anteriormente. Debido a que necesitan integrar sus propias estrategias con estas estrategias sincronizadas, y las estrategias pueden necesitar ser cambiadas drásticamente, lo que costará mucho trabajo y esfuerzo. ¿Hay una buena manera de actualizar algunas de sus estrategias maduras directamente a la función de sincronización de orden? Soluciones: Puede diseñar una biblioteca de clases de plantilla de sincronización de orden (laOrder Synchronization Management System Class Library (Single Server)estrategia en el sistema diseñado en este artículo), de modo que el propietario de la cuenta de referencia (orden-líder) puede incrustar esta biblioteca de clases de plantilla en su propia estrategia directamente para lograr la función de sincronización de orden y posición.
    1. Reducir un bot real adicional. El último inconveniente es que si se utilizan las 2 órdenes pasadas, la estrategia de sincronización de posiciones descrita anteriormente. Es necesario abrir un bot real adicional para monitorear las posiciones de la cuenta de referencia (cuenta para líderes de orden). Soluciones: Utilice la biblioteca de clases de plantilla para incrustar funcionalidades en la estrategia de cuenta de referencia.

Así que el sistema consta de 2 partes:

  1. Biblioteca de clases del sistema de gestión de sincronización de pedidos (Solo servidor)
  2. Sistema de gestión de sincronización de pedidos (servidor sincrónico)

Una vez que hayamos definido nuestras necesidades, empecemos a diseñar!

Diseño 1: biblioteca de clases del sistema de gestión de sincronización de pedidos (servidor único)

Tenga en cuenta que esta no es una estrategia. Es una biblioteca de clases de plantilla de FMZ. El concepto de una biblioteca de clases de plantilla se puede buscar en la documentación de la API de FMZ y no lo repetiremos de nuevo.

Código de la biblioteca de clases de plantilla:

// Global variables
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 the position
        var tradeDirection = type == PD_LONG ? "buy" : "sell"
        // send signals
        msg = symbol + "," + ct + "," + tradeDirection + "," + Math.abs(delta)        
    } else if (delta < 0) {
        // close the position
        var tradeDirection = type == PD_LONG ? "closebuy" : "closesell"
        if (nowAmount <= 0) {
            Log("no positions found")
            return 
        }
        // send signals
        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 the 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 future-following is supported"
    }

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

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

        // monitor positions
        var keyInitRefPosAmount = "refPos-" + exIndex + "-" + symbol + "-" + ct    // refPos-exIndex-symbol-contractType
        var initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        if (!initRefPosAmount) {
            // no initialization data, initialize it
            mapInitRefPosAmount[keyInitRefPosAmount] = getPosAmount(_C(ex.GetPosition), ct)
            initRefPosAmount = mapInitRefPosAmount[keyInitRefPosAmount]
        }

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

        // detect changes
        if (!(longPosDelta == 0 && shortPosDelta == 0)) {
            // Perform long positions
            if (longPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Perform long position-following, changes in volume:", longPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_LONG, longPosDelta)
            }
            // Perform short positions
            if (shortPosDelta != 0) {
                Log(ex.GetName(), ex.GetLabel(), symbol, ct, "Perform short position-following, changes in volume:", shortPosDelta)
                follow(nowRefPosAmount, symbol, ct, PD_SHORT, shortPosDelta)
            }

            // Update after performing the order-following operation
            mapInitRefPosAmount[keyInitRefPosAmount] = nowRefPosAmount
        }

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

$.getTbl = function() {
    var tbl = {
        "type" : "table", 
        "title" : "synchronization of data", 
        "cols" : [], 
        "rows" : []
    }
    // construct the table headers
    tbl.cols.push("monitor the account: refPos-exIndex-symbol-contractType")
    tbl.cols.push(`monitor the position: {"timestamp":xxx,"long positions":xxx,"short positions":xxx}`)
    _.each(fmzExtendApis, function(extendApiData, index) {
        tbl.cols.push(keyName_robotId + "-" + index)
    })
    
    // Write data in
    _.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
}

// Example of the strategy call that references the template class library
function main() {
    // Clear all logs
    LogReset(1)

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

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

    // Timed trading interval
    var tradeInterval = 1000 * 60 * 3        // Trade for every three minutes to observe the order-following signals
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strategy...

        // Simulated trading triggers for testing
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Trade the simulation order-leading strategies, position changes", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Interface functions that use templates
        $.PosMonitor(0, "ETH_USDT", "swap")    // Multiple monitors can be set up to monitor different exchange objects on the order-following strategy  
        var tbl = $.getTbl()
        
        // Display status bar
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

El diseño es muy simple, la biblioteca de clases tiene 2 funciones funcionales.Order Synchronization Management System Class Library (Single Server)Entonces la estrategia puede utilizar las siguientes funciones.

  • - ¿Qué es eso? El objetivo de esta función es monitorear los cambios de posición de los objetos de intercambio en la estrategia y luego enviar señales de negociación al mercado real de bots establecidos en los parámetros de la plantilla: Biblioteca de clases de Order Synchronization Management System (Single Server).

  • $. GetTbl. ¿ Qué quieres decir? Vuelva a los datos de sincronización monitoreados.

Un ejemplo de uso es el de lamainfunción de la librería de clases del modelo de sistema de gestión de sincronización de pedidos (servidor único):

// Example of the strategy call that references the template class library
function main() {
    // Clear all logs
    LogReset(1)

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

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

    // Timed trading interval
    var tradeInterval = 1000 * 60 * 3        // Trade for every three minutes to observe the order-following signals
    var lastTradeTS = new Date().getTime()
    
    while (true) {
        // Other logic of the strategy...

        // Simulated trading triggers for testing
        var ts = new Date().getTime()
        if (ts - lastTradeTS > tradeInterval) {
            Log("Trade the simulation order-leading strategies, position changes", "#FF0000")
            exchanges[0].SetDirection("buy")
            exchanges[0].Buy(-1, 1)
            lastTradeTS = ts
        }

        // Interface functions by using templates
        $.PosMonitor(0, "ETH_USDT", "swap")    // Multiple monitors can be set up to monitor different exchange objects on the order-following strategy  
        var tbl = $.getTbl()
        
        // Display status bar
        LogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")
        Sleep(1000)
    }
}

Una biblioteca de clases de plantilla también puede crear un bot real de estrategia por sí mismo, que generalmente se utiliza para probar la biblioteca de clases de plantilla, como la prueba de la plantilla.mainLa función en una plantilla es lamainfunción de una de sus propias estrategias.

El código de prueba se escribe usando la demostración de OKEX para probar, necesita configurar la clave de API de demostración de OKEX en FMZ como una cuenta de referencia (orden-leading), y comienza a cambiar a demostración en la función principal. Luego, establezca el par de operaciones en ETH_USDT y establezca el contrato para intercambiar. Luego, entra en un bucle de tiempo. En el bucle, se coloca una orden cada 3 minutos para simular el desencadenamiento de las transacciones de estrategia.$.PosMonitor(0, "ETH_USDT", "swap")Cuando se llama en el bucle de mientras, el primer parámetro de esta función se pasa a 0, lo que significa monitorear los intercambios de objetos de intercambio[0], monitorear el par de operaciones ETH_USDT, contrato de intercambio.$.getTbl()para obtener información del gráfico, utilizandoLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")para hacer que los datos del gráfico se muestren en la barra de estado.

Así que podemos ver que podemos hacer que la estrategia tenga la capacidad de monitorear las posiciones de una especie determinada, y los cambios de posición para enviar mensajes utilizando$.PosMonitor(0, "ETH_USDT", "swap")En el caso de las entidades de crédito, el valor razonable de las pérdidas y pérdidas derivadas de las operaciones de crédito se determinará en función de la situación de las pérdidas.

Antes de probar, vamos a explicar el diseño de los parámetros de estrategia de laOrder Synchronization Management System Class Library (Single Server)¿ Qué pasa? Acabamos de hablar de cómo utilizar la función de interfaz de una plantilla para actualizar una estrategia para tener una función de orden de liderazgo. La cuestión de a quién enviar está configurada por los parámetros de laOrder Synchronization Management System Class Library (Single Server).

img

Podemos ver que hay 5 parámetros, soportando hasta 5 empujes (se puede extender por sí mismos si necesita aumento), los parámetros predeterminados son cadenas vacías, es decir, no procesados.

  • etiqueta Una etiqueta para una cuenta de sincronización, se utiliza para establecer una etiqueta para una cuenta con un nombre que se puede establecer a voluntad.

  • El robot Identificación del robot, la identificación de laOrder Synchronous ServerUn bot real creado por el propietario de la cuenta sincronizada.

  • Acceso clave Acceso ampliado a la APIChiave de FMZ

  • Secreto Secreto de la API extendidaLa clave de FMZ

El código temporal del sistema de gestión de sincronización de pedidos (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

Podemos ver que el bot real del dueño de la cuenta sincronizada recibió el mensaje:ETH_USDT,swap,buy,1¿ Qué pasa? Entonces nos permitirá hacer nuestro propio orden automático-siguiendo en el siguiente paso basado en los pares tradiing, códigos de contrato, direcciones comerciales, y la cantidad en la información.

Hasta ahora, elOrder Synchronization Management System (Synchronous Server)es el código temporal, seguiremos explorando su diseño en el próximo número.


Relacionados

Más.