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

Автор:Лидия., Создано: 2022-11-07 10:20:01, Обновлено: 2023-09-15 20:45:23

img

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

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

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

Идеи дизайна

Во-первых, нам нужны некоторые хорошие предложения и потребности.

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

    Решения: Используя расширенный API-интерфейс FMZ, владельцу синхронизированного аккаунта (последователю заказов) нужно только зарегистрировать аккаунт на платформе FMZ Quant Trading, а затем запустить стратегию (в системе, разработанной в этой статье:Order Synchronous ServerПосле этого просто предоставьте FMZ расширенный API KEY (заметьте, что это не API KEY обменной учетной записи) и Order Synchronous Server реальный бот ID владельцу ссылки учетной записи (руководитель заказа). Когда владелец счета ссылки (следовал за заказом) реальный бот (счетчик)Order Synchronization Management System Class Library (Single Server)в системе, разработанной в этой статье) посылает сигнал, владелец синхронизированного счета реальный бот получит торговый сигнал и автоматически разместит следующий заказ.

    1. Многие разработчики имеют хорошие стратегии, но они не могут использовать 2 стратегии синхронизации порядка и положения, описанные выше. Потому что им нужно интегрировать свои собственные стратегии с этими синхронизированными стратегиями, и стратегии могут потребоваться радикально изменить, что будет стоить много работы и усилий. Есть ли хороший способ обновить некоторые из ваших зрелых стратегий непосредственно на функцию синхронизации порядка? Решения: Вы можете разработать библиотеку классов шаблонов синхронизации порядка (Order Synchronization Management System Class Library (Single Server)Стратегия в системе, разработанной в этой статье), так что владелец учетной записи ссылки (руководитель заказа) может встроить эту библиотеку классов шаблона в свою собственную стратегию непосредственно для достижения функции синхронизации порядка и положения.
    1. Уменьшить число реальных ботов. Последний недостаток заключается в том, что если вы используете 2 прошлых ордера, стратегия синхронизации позиций описана выше. Необходимо открыть дополнительный реальный бот для мониторинга позиций ссылочного аккаунта (аккаунт для лидеров ордеров). Решения: Используйте библиотеку классов шаблонов для встраивания функциональности в стратегию учетной записи ссылки.

Так что система состоит из 2 частей:

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

Как только мы определим наши потребности, давайте начнем проектировать!

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

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

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

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

Дизайн очень прост, библиотека классов имеет 2 функциональных функции.Order Synchronization Management System Class Library (Single Server). Тогда стратегия может использовать следующие функции.

  • $. Позиционный монитор. Цель этой функции - отслеживать изменения позиции обменных объектов в стратегии, а затем отправлять торговые сигналы на реальный ботный рынок, установленный в параметрах шаблона: библиотека классов системы управления синхронизацией заказов (один сервер).

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

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

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

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

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

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

Перед испытаниями мы объясним стратегические параметры проектированияOrder Synchronization Management System Class Library (Single Server)- Да, конечно. Мы только что говорили о том, как использовать функцию интерфейса шаблона для обновления стратегии, чтобы иметь функцию управления заказами. Вопрос о том, кого отправить, определяется параметрамиOrder Synchronization Management System Class Library (Single Server).

img

Мы можем видеть, что есть 5 параметров, поддерживающих до 5 толканий (это может быть расширено сами по себе, если это необходимо увеличение), параметры по умолчанию являются пустыми строками, то есть не обрабатываются.

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

  • робот Идентификатор робота, идентификаторOrder Synchronous ServerНастоящий бот, созданный владельцем синхронного аккаунта.

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

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

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

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

img

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

До сих порOrder Synchronization Management System (Synchronous Server)является временным кодом, мы продолжим исследовать его дизайн в следующем выпуске.


Связанные

Больше