Diseño de un sistema de gestión sincronizada de pedidos basado en la FMZ

El autor:Un sueño pequeño., Creado: 2022-02-14 19:46:30, Actualizado: 2023-09-15 20:44:11

img

Diseño de un sistema de gestión sincronizada de pedidos basado en la FMZ

En artículos anteriores de la biblioteca FMZ, hemos diseñado varias estrategias de sincronización de pedidos y almacenamiento.

Estas son las cuentas de referencia y las cuentas de sincronización en una sola estrategia para administrar la implementación de órdenes, sincronizar las existencias. Hoy vamos a probar un diseño un poco diferente, basado en la potente extensión de la interfaz API de la plataforma de comercio cuantitativo FMZ, y vamos a diseñar un sistema de gestión de sincronización de órdenes.

La idea del diseño

Primero necesitamos algunas buenas recomendaciones, necesidades. Los dos pedidos anteriores, la estrategia de sincronización de almacenamiento, tienen algunos puntos débiles evidentes, que vamos a discutir juntos:

  • 1, el implementador de la política de sincronización en vivo, debe tener el API KEY de la bolsa de cuentas de referencia, el API KEY de la bolsa de cuentas de sincronización. El problema con el escenario de uso es que no hay problema en que una cuenta de otro intercambio siga a una cuenta propia. Pero puede ser problemático en el caso de una cuenta de referencia y una cuenta sincronizada que no sea una cuenta de propietario. Los propietarios de cuentas sincronizadas a veces no están dispuestos a proporcionar la clave API de su cuenta de intercambio por razones de seguridad.

    La solución: Utilizando la API de extensión de FMZ, los propietarios de cuentas de sincronización (los suscriptores) solo necesitan registrarse en la plataforma de operaciones cuantitativas de FMZ y luego ejecutar una de las políticas (en el sistema diseñado para este artículo):订单同步管理系统(Synchronous Server)La política de disco) ; luego puede proporcionar el KEY de API de FMZ (no el KEY de API de la cuenta de la bolsa) y el ID de disco del sistema de gestión de órdenes sincronizado (el servidor sincrónico) al propietario de la cuenta de referencia (el cliente). Cuando se hace referencia a los titulares de cuentas (bandas) en el disco físico (sistemas diseñados para este artículo)订单同步管理系统类库(Single Server)En la actualidad, el número de transacciones que se realizan en una cuenta sincronizada es el número de transacciones que se realizan en una cuenta sincronizada.

  • 2, Muchos desarrolladores tienen mejores estrategias y no pueden usar las dos órdenes anteriores descritas anteriormente, las estrategias de sincronización de almacenamiento. Debido a que esto requiere la combinación de sus propias estrategias con estas estrategias de sincronización, es posible que la estrategia necesite grandes cambios y esfuerzos. ¿Hay una buena manera de actualizar directamente algunas de sus estrategias más sólidas a la sincronización de órdenes? La solución: Se puede diseñar una librería de clases de plantillas sincronizadas de pedido (en el sistema diseñado para este artículo)订单同步管理系统类库(Single Server)Las políticas de los propietarios de las cuentas de referencia (las bandas) pueden integrar directamente esta librería de modelos en sus propias políticas para implementar la función de sincronización de pedidos y almacenamiento.

  • 3 ∞ Reducción de un disco físico adicional ∞ El último punto de dolor es que si se utilizan las dos órdenes de futuros descritas anteriormente, la estrategia de sincronización de tenencia; se requiere abrir una cuenta de tenencia adicional de referencia de monitoreo en vivo (cuenta de banda). La solución: Utiliza la biblioteca de modelos para integrar funciones en la política de cuentas de referencia.

Así que el sistema se compone de dos partes: 1, el sistema de gestión de ordenes sincronizado (Single Server) 2. Sistemas de gestión de órdenes sincronizadas (Synchronous Server)

Si tienes una idea clara de lo que necesitas, empieza a diseñar.

Diseño 1: Sistema de gestión de orden sincronizado de la biblioteca de clases (Single Server)

Tenga en cuenta que esta no es una política; sino una biblioteca de modelos de FMZ, y el concepto de biblioteca de modelos se puede buscar en la documentación de la API de FMZ, que no se describe aquí.

El código de la biblioteca de clases de plantillas:

// 全局变量
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)
    }
}

La librería de clases tiene dos funciones de diseño muy sencillo.订单同步管理系统类库(Single Server)Después de la librería de clases de plantillas. Esta política puede utilizarse con la siguiente función.

  • $ PosMonitor El papel de esta función es el de monitorear los cambios de posicionamiento de los objetos de los intercambios en la política, y luego enviar señales de transacción a un disco real configurado en los parámetros de la librería de sistemas de gestión de órdenes sincronizadas ("Single Server").

  • ¿Qué es lo que está pasando? La información de los datos sincronizados de los monitores es devuelta.

Un ejemplo de uso es el de la librería de sistemas de gestión de sincronización de pedidos (template Single Server).mainEn la función:

// 引用该模板类库的策略调用范例
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)
    }
}

Una librería de clases de plantillas puede también crear su propia plataforma de políticas, que se utiliza generalmente para probar librerías de clases de plantillas. Por ejemplo, para probar la librería de clases de plantillas.mainUna función es una estrategia para usted.mainLa función.

El código de prueba fue escrito para probar el disco OKEX, requiriendo configurar el API KEY del disco OKEX en FMZ como la cuenta de referencia (la banda), iniciar el cambio al disco en la función principal. Luego, configurar el par de transacciones como ETH_USDT, configurar el contrato como permanente (el swap). Luego, entrar en un ciclo de mientras.$.PosMonitor(0, "ETH_USDT", "swap")El primer parámetro de esta función que se llama es 0, lo que significa que el objeto de esta bolsa, que vigila el intercambio de ETH_USDT, vigila el par de transacciones, el contrato de cambio; y luego se llama$.getTbl()Obtener información de gráficos y usarlaLogStatus(_D(), "\n" + "`" + JSON.stringify(tbl) + "`")Para que los datos del gráfico aparezcan en la barra de estado.

Así que, ya ves, si se usa en alguna de las estrategias que hacen referencia a la plantilla, entonces se puede usar en cualquier de las estrategias que hacen referencia a la plantilla, así que se puede usar en cualquier de las estrategias que hacen referencia a la plantilla.$.PosMonitor(0, "ETH_USDT", "swap")En este caso, la estrategia puede tener la función de monitorear el almacenamiento de una variedad, el almacenamiento cambia para impulsar el mensaje.

Antes de hacer la prueba, expliquen.订单同步管理系统类库(Single Server)El diseño de los parámetros de la estrategia: Acabamos de hablar de cómo usar las funciones de interfaz de la plantilla para que una estrategia sea actualizada con una función de banda. La pregunta de a quién enviarlos está en manos de la gente.订单同步管理系统类库(Single Server)Los parámetros de la configuración.

img

Se puede ver que hay 5 parámetros, con un máximo de 5 soportes de empuje (se puede ampliar automáticamente si se necesita), los parámetros son por defecto una cadena vacía, es decir, no se procesan.

  • etiqueta Etiquetas de cuentas sincronizadas, para marcar una cuenta, con un nombre que se puede configurar como sea.

  • El robotId ID de disco físico, creado por el propietario de la cuenta de sincronización订单同步管理系统(Synchronous Server)La identificación del disco físico.

  • accesoKey AccessKey para la extensión de la API de FMZ

  • La clave secreta La clave secreta de la API de FMZ

Después podemos hacer una prueba sencilla.

La biblioteca de clases del sistema de administración de órdenes sincronizada (Single Server) se ejecuta en el disco:

img

El servidor sincronizado recibió una señal: El sistema de gestión de pedidos sincronizados (Synchronous Server) aún no está diseñado, lo implementamos con un código simple, no hace transacciones, solo imprime señales:

El sistema de gestión de órdenes sincronizado (Synchronous Server) Código provisional:

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

img

El mensaje que se puede ver en el disco de los dueños de las cuentas sincronizadas es:ETH_USDT,swap,buy,1¿Qué es esto? El siguiente paso es hacer su propio seguimiento automático de acuerdo con el par de transacciones, el código del contrato, la dirección de la transacción y el número de transacciones en la información.

Ahora mismo订单同步管理系统(Synchronous Server)Es sólo un código provisional, vamos a seguir con su diseño en el próximo número.


Relacionados

Más.

el mismo número de unidades.Para implementar un registro, se necesitan dos discos, uno de clase y otro de orden.

el mismo número de unidades.Hecho según el tutorial, muestra un error de configuración

¿Qué es esto?¿Qué parámetros se deben cambiar en la lista inversa?

¿Qué es esto?¿Pueden combinarse los dos discos reales para usarlos juntos?

Un sueño pequeño.Tal vez no entiendas el artículo, esta biblioteca de clases es una herramienta que se puede integrar directamente en la línea de políticas de los usuarios, y luego la política tiene la función de banda, envía mensajes a las cuentas de contabilidad configuradas, y los robots reciben mensajes de lista. En pocas palabras, ese es el escenario.

Un sueño pequeño.Puede ver el artículo, información de configuración: etiqueta, ID de disco real, accesskey, secretkey.

el mismo número de unidades.Error configs error!, en la librería del sistema de administración de sincronización de pedidos (Single Server), se completa el disco de usuario y las 2 claves, y luego se hace referencia al disco de administración de sincronización de pedidos (Single Server), ¡error, error configs error!

el mismo número de unidades.¡Error de configuración!

Un sueño pequeño.En la página web de la organización, se puede leer más información sobre los errores reportados.

Un sueño pequeño.Los medios de comunicación locales han estado haciendo un llamado para que se modifique la estrategia.

Un sueño pequeño.El código es abierto, puedes modificarlo según tus necesidades y puedes hacerlo.