4
Подписаться
1271
Подписчики

Разработка системы управления синхронизацией заказов на основе квантификации FMZ (1)

Создано: 2022-02-14 19:46:30, Обновлено: 2025-05-16 16:36:53
comments   11
hits   1939

Разработка системы управления синхронизацией заказов на основе квантификации FMZ (1)

Разработка системы управления синхронизацией заказов на основе квантификации FMZ (1)

В предыдущих статьях библиотеки FMZ мы разработали несколько стратегий синхронизации заказов и позиций.

Они предназначены для объединения справочного счета и счета синхронизации в одну стратегию для управления и синхронизации заказов и позиций. Сегодня мы попробуем другой дизайн. На основе мощного расширенного API-интерфейса количественной торговой платформы FMZ мы разработаем систему управления синхронизацией заказов.

Идеи дизайна

Прежде всего нам нужны хорошие предложения и потребности. Две предыдущие стратегии синхронизации заказов и позиций имеют несколько очевидных болевых точек. Давайте обсудим их вместе:

  • 1. Реализатор стратегии синхронизации должен иметь API-ключ обмена референтной учетной записи и API-ключ обмена учетной записи синхронизации. Сценарий использования этого вопроса следующий: для ваших других аккаунтов на бирже не составит труда подписаться на один из ваших аккаунтов. Однако возникнут проблемы, если у ссылочной учетной записи и учетной записи синхронизации не будет одного и того же владельца. Иногда из соображений безопасности владелец синхронизированной учетной записи не желает предоставлять API KEY своей учетной записи на бирже. Но как я могу размещать заказы синхронно, не предоставляя API KEY?

Решение: Используя расширенный API-интерфейс FMZ, владельцу учетной записи синхронизации (подписчику) необходимо только зарегистрировать количественную торговую платформу FMZ, а затем запустить стратегию (в системе, разработанной в этой статье:订单同步管理系统(Synchronous Server)Стратегия реального рынка). Затем предоставьте расширенный API-ключ FMZ (обратите внимание, не API-ключ учетной записи биржи) и идентификатор системы управления синхронизацией заказов (синхронный сервер) в реальном времени владельцу ссылочной учетной записи (лицу, которое размещает заказ). . При ссылке на реальный заказ владельца аккаунта (того, у которого есть заказ) (в системе, разработанной в этой статье)订单同步管理系统类库(Single Server)) отправляет сигнал, реальный счет владельца синхронизированного счета получит торговый сигнал и автоматически разместит ордер.

    1. У многих разработчиков есть лучшие стратегии, но они не могут использовать две предыдущие стратегии синхронизации порядка и позиции, описанные выше. Потому что это потребовало бы интеграции собственной стратегии с этими стратегиями синхронизации, и стратегию, возможно, пришлось бы пересмотреть, что потребовало бы много времени и усилий. Есть ли хороший способ обновить некоторые из моих зрелых стратегий непосредственно до функции синхронизации заказов? Решение: Вы можете разработать библиотеку шаблонов синхронизации заказов (система, разработанная в этой статье)订单同步管理系统类库(Single Server)Стратегия), позволяющая владельцу ссылочного аккаунта (лицу, принимающему заказ) напрямую встраивать эту библиотеку шаблонов в свою собственную стратегию для реализации функции синхронизации заказов и позиций.
    1. Уменьшите один дополнительный реальный заказ. Последняя проблема возникает, если вы используете две стратегии синхронизации прошлых заказов и позиций, описанные выше. Необходимо открыть дополнительный реальный счет для мониторинга позиций референтного счета (при наличии единого счета). Решение: Используйте библиотеку шаблонов для встраивания функциональности в стратегии реферальных счетов.

Итак, эта система состоит из 2 частей: 1. Библиотека классов системы управления синхронизацией заказов (один сервер) 2. Система синхронного управления заказами (синхронный сервер)

Теперь, когда требования ясны, давайте приступим к проектированию!

Проект 1: Библиотека классов системы управления синхронизацией заказов (один сервер)

Обратите внимание, что это не стратегия. Это библиотека шаблонных классов FMZ. Концепцию библиотеки шаблонных классов можно найти в документации API FMZ, поэтому я не буду здесь вдаваться в подробности.

Код библиотеки шаблонов:

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

Конструкция очень проста, эта библиотека классов имеет 2 функциональные функции. Когда программная торговая стратегия на платформе FMZ ссылается订单同步管理系统类库(Single Server)После библиотеки шаблонов. Эту стратегию можно реализовать с помощью следующей функции.

  • $.PosMonitor Функция заключается в отслеживании изменений позиции биржевого объекта в стратегии, а затем отправке торговых сигналов на реальный рынок, заданных в параметрах шаблона: Библиотека классов системы управления синхронизацией ордеров (один сервер).

  • $.getTbl Возвращает отслеживаемые данные синхронизации.

Пример использования: Шаблон библиотеки классов системы управления синхронизацией заказов (один сервер)mainВ функции:

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

Библиотека шаблонов сама по себе может создавать реальные стратегии, которые обычно используются для тестирования библиотеки шаблонов. Например, тест этого шаблона. Вы можете понять шаблонmainФункция — это ваша собственная стратегия.mainфункция.

Тестовый код написан для использования теста симуляционного диска OKEX. Необходимо настроить API KEY симуляционного диска OKEX на FMZ как справочный счет (с заказами), и начать переключение на симуляционный диск в основной функции. Затем установите торговую пару на ETH_USDT, а контракт — на бессрочный (своп). Затем введите цикл while. Ордер размещается каждые 3 минуты в цикле, чтобы имитировать запуск стратегической торговли. Цикл while вызывает$.PosMonitor(0, "ETH_USDT", "swap")Первый параметр этой функции передается как 0, что указывает на мониторинг обменов.[0] Этот объект обмена отслеживает торговую пару ETH_USDT и контракт своп. Тогда позвони$.getTbl()Чтобы получить информацию о диаграмме, используйтеLogStatus(_D(), "\n" + "” + JSON.stringify(tbl) + “")Позволяет отображать данные диаграммы в строке состояния.

Итак, вы видите, пока вы используете его в политике, которая ссылается на этот шаблон$.PosMonitor(0, "ETH_USDT", "swap")стратегия может быть оснащена функцией мониторинга позиций определенного товара и отправки сообщений по изменению позиций.

Перед тестированием, пожалуйста, объясните订单同步管理系统类库(Single Server)Разработка параметров стратегии: Я только что рассказал о том, как использовать функцию интерфейса шаблона, чтобы включить в обновление стратегии единственную функцию. Так кому же посылается сигнал при изменении положения? Кому адресован этот вопрос, определяется订单同步管理系统类库(Single Server)Параметры для настройки.

Разработка системы управления синхронизацией заказов на основе квантификации FMZ (1)

Вы видите, что имеется 5 параметров, поддерживающих до 5 push-запросов (при необходимости их можно расширить), а параметр по умолчанию представляет собой пустую строку, что означает, что он не обрабатывается. Формат строки конфигурации: label, robotId, accessKey, secretKey

  • label Метка синхронизированной учетной записи используется для обозначения определенной учетной записи, а имя можно задать по желанию.

  • robotId Настоящий идентификатор, созданный владельцем учетной записи синхронизации订单同步管理系统(Synchronous Server)Идентификатор фактической транзакции.

  • accessKey Расширенный API-ключ доступа FMZ

  • secretKey Расширенный API-ключ FMZ secretKey

Далее мы можем провести простой тест.

Система управления синхронизацией заказа библиотеки классов (один сервер) работа реального диска:

Разработка системы управления синхронизацией заказов на основе квантификации FMZ (1)

Система управления синхронизацией заказов (Синхронный сервер) получила сигнал: Мы еще не закончили проектирование системы управления синхронизацией заказов (Synchronous Server). Давайте сначала реализуем ее с помощью простого кода, который не совершает транзакции, а только выводит сигналы:

Временный код системы управления синхронизацией заказов (Синхронный сервер):

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

Разработка системы управления синхронизацией заказов на основе квантификации FMZ (1)

Вы можете видеть, что реальный аккаунт владельца учетной записи синхронизации получил информацию:ETH_USDT,swap,buy,1。 Таким образом, следующим шагом будет автоматическое выполнение заказа на основе торговой пары, кода контракта, направления торговли и количества, указанных в информации.

в настоящий момент订单同步管理系统(Synchronous Server)Это всего лишь временный код, мы продолжим изучать его дизайн в следующем выпуске.