Diseño de un sistema de gestión sincrónica basado en órdenes FMZ (1)

El autor:No lo sé., Creado: 2022-04-06 15:08:26, Actualizado: 2022-04-24 18:00:51

Diseño de un sistema de gestión sincrónica basado en órdenes FMZ (1)

En los artículos anteriores de FMZ Digest, hemos diseñado varias estrategias sincrónicas de orden y posición.

Estos diseños toman la cuenta de referencia y la cuenta síncrona en la misma estrategia para ser administrados para realizar la sincronización de órdenes y posiciones.

El pensamiento de diseño

En primer lugar, necesitamos algunas buenas sugerencias y requisitos. Las dos estrategias de sincronización de órdenes y posiciones anteriores tienen varias desventajas obvias.

  • 1.Los usuarios que implementan la sincronización de estrategias de bots deben disponer de la clave API de la plataforma de cuenta de referencia y de la clave API de la cuenta de sincronización. Para el escenario de uso, el problema es: está bien que sus otras cuentas de la plataforma sigan una de sus propias cuentas. Pero puede ser problemático para el escenario en el que la cuenta de referencia y la cuenta de sincronización no tienen el mismo propietario. El propietario de la cuenta de sincronización a veces no está dispuesto a proporcionar la clave API de su cuenta de la plataforma debido a consideraciones de seguridad. Pero ¿cómo colocar un pedido para operar sincronizadamente sin proporcionar la clave API?

    Solución: Utilice la API ampliada de FMZ, el propietario de la cuenta de sincronización (el supervisor de órdenes) solo necesita registrar la plataforma de negociación FMZ Quant y luego ejecutar una estrategia (en el sistema diseñado en este artículo:Order Synchronous Management System (Synchronous Server)Luego, la clave API extendida de FMZ (tenga en cuenta que no es la clave API de la cuenta de la plataforma) y el ID de bot del sistema de gestión de sincronización de pedidos (servidor síncrono) se proporcionarán al propietario de la cuenta de referencia (el propietario de pedidos). Cuando el bot del titular de la cuenta de referencia (el titular de la orden) (Order Synchronous Management System Library (Single Server)El bot del propietario de la cuenta de sincronización recibirá la señal de negociación y la orden se colocará automáticamente más tarde.

  • 2.Muchos desarrolladores tienen mejores estrategias y no pueden usar las dos estrategias anteriores de sincronización de orden y posición descritas anteriormente. Debido a que eso necesita fusionar sus propias estrategias con estas estrategias de sincronización, y sus estrategias pueden necesitar ser muy modificadas, lo que consume mucho tiempo y mano de obra. ¿Hay una buena manera de actualizar directamente algunas de sus estrategias maduras a las que tienen la función de sincronización de orden?

    Solución: Puede diseñar una biblioteca de plantillas sincronizadas de orden (elOrder Synchronous Management System Library (Single Server)La estrategia en el sistema diseñado en el artículo), de modo que el propietario de la cuenta de referencia (el propietario del pedido) puede insertar directamente esta biblioteca de plantillas en su propia estrategia para lograr la sincronización de orden y posición.

  • 3.Reducir el número de robots adicionales La última desventaja es que si utiliza las dos órdenes anteriores y las estrategias de sincronización de posición descritas anteriormente, es necesario abrir una posición adicional de la cuenta de referencia (cuenta con órdenes) para el monitoreo de bots. Solución: Utilice la biblioteca de plantillas para incrustar la función en la estrategia de cuenta de referencia.

Por lo tanto, el sistema consta de dos partes: 1.Biblioteca de sistemas de gestión sincrónica de pedidos (servidor único) 2.Sistema de gestión sincrónica de pedidos (servidor sincrónico)

Una vez que nos aseguremos de nuestras demandas, ¡comencemos a diseñar!

Diseño 1: Biblioteca de sistemas de gestión sincrónica de orden (servidor único)

Tenga en cuenta que aquí no es una estrategia, sino una biblioteca de plantillas FMZ, que se puede buscar en la documentación de la API FMZ y no discutiremos aquí.

En el caso de las entidades de crédito, el valor de la entidad de crédito es el valor de la entidad de crédito.

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

El diseño es muy simple, la biblioteca tiene 2 funciones.Order Synchronous Management System Library (Single Server)Esta estrategia puede entonces utilizar las siguientes funciones.

  • $. Posmonitor El efecto 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 bot establecido en los parámetros de la plantilla: biblioteca de sistemas de gestión sincrónica de orden (Sistema único de servidor).
  • - ¿Qué quieres decir? La función devuelve los datos síncronos monitoreados.

El ejemplo de uso está en elmainfunción en la biblioteca del sistema de gestión sincrónica de pedidos (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)
    }
}

Una librería de plantillas puede crear un bot de estrategia, que se utiliza generalmente para probar la librería de plantillas.mainLa función en la plantilla es lamainfunción de una de sus propias estrategias.

El código de prueba se escribe para usar el bot simulado de OKEX para probar, y la clave API del bot simulado de OKEX debe configurarse en FMZ como una cuenta de referencia (con órdenes), y la función principal comienza a cambiar al bot simulado. Luego, establece el par de operaciones en ETH_USDT, y establece el contrato para intercambiar. Luego, ingrese un bucle de tiempo. En el bucle, se coloca una orden cada 3 minutos para simular el desencadenante de las operaciones de estrategia.$.PosMonitor(0, "ETH_USDT", "swap")se llama en el bucle mientras, y el primer parámetro de la función llamada es 0, lo que significa monitorear los intercambios de objetos de intercambio[0], el par de operaciones ETH_USDT y el contrato de intercambio.$.getTbl()para obtener la información del gráfico, y utilizarLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")para hacer que los datos del gráfico se muestren en la barra de estado.

Así que verás, mientras$.PosMonitor(0, "ETH_USDT", "swap")Cuando el símbolo se utiliza en una estrategia que llama a la plantilla, la estrategia puede tener la función de monitorear la posición de un cierto símbolo y enviar el mensaje de cambio de posición.

Antes del ensayo, explicar el diseño de los parámetros delOrder Synchronous Management System Library (Single Server)Estrategia: Acabo de hablar de cómo usar la función de interfaz de la plantilla para hacer una actualización de estrategia con una función de llevar órdenes. La cuestión de a quién enviar está configurada por los parámetros deorder synchronous management system library (Single Server).

img

Puede ver cinco parámetros, que pueden soportar un máximo de cinco empujados (si necesita aumentar el número de empuje, puede extenderlo usted mismo); el valor predeterminado de los parámetros es una cadena vacía, es decir, no procesada.

  • etiqueta La etiqueta de la cuenta sincrónica, utilizada para etiquetar una cuenta; el nombre de la etiqueta se puede establecer al azar.

  • - ¿Qué quieres? El bot ID; el bot ID delorder synchronous management system (Synchronous Server)Creado por el propietario de la cuenta sincrónica.

  • Acceso clave La clave de acceso de la API ampliada de FMZ.

  • SecretKey (clave secreta) La clave secreta de la API ampliada de FMZ.

Entonces, podemos operar una prueba simple.

Ordenar la operación del bot de la biblioteca del sistema de gestión sincronizado (servidor único):

img

El bot del sistema de gestión de orden sincrónico (servidor sincrónico) recibió la señal: Orden Sistema de Gestión Sincrónico (Servidor Sincrónico) ahora no ha sido completamente diseñado por nosotros, y podemos utilizar un código simple para realizarlo, sin comercio, sólo la señal de impresión:

Código temporal del sistema de gestión sincrónica de pedidos (servidor sincrónico):

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

img

Como pueden ver, el bot del dueño de la cuenta sincronizada recibió el mensaje:ETH_USDT,swap,buy,1¿ Qué pasa? Por lo tanto, en el siguiente paso, podemos supervisar las órdenes automáticamente, de acuerdo con el par de operaciones, código del contrato, dirección de operaciones y volumen.

Actualmente,order synchronous management system (Synchronous Server)es sólo un código temporal, y podemos discutir más sobre su diseño en el siguiente artículo.


Más.