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

Автор:Нинабадасс., Создано: 2022-04-06 15:08:26, Обновлено: 2022-04-24 18:00:51

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

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

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

Мышление дизайна

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

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

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

  • 2.Многие разработчики имеют лучшие стратегии и не могут использовать две предыдущие стратегии синхронизации порядка и позиции, описанные выше. Потому что это необходимо объединить свои собственные стратегии с этими стратегиями синхронизации, и их стратегии могут потребоваться значительно изменить, что занимает много времени и трудоемко. Есть ли хороший способ напрямую обновить некоторые из ваших зрелых стратегий к тем, которые имеют функцию синхронизации порядка?

    Решение: Вы можете создать синхронную библиотеку шаблонов (Order Synchronous Management System Library (Single Server)Схема, разработанная в статье, позволяет владельцу учетной записи (владельцу заказа) напрямую вставлять эту библиотеку шаблонов в свою стратегию для синхронизации порядка и позиции.

  • 3.Уменьшить количество дополнительных ботов Последний недостаток заключается в том, что при использовании двух предыдущих стратегий синхронизации ордеров и позиций, описанных выше, для мониторинга ботов необходимо открыть дополнительную позицию ссылочного счета (счета с ордерами). Решение: Используйте библиотеку шаблонов для встраивания функции в стратегию учетной записи ссылки.

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

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

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

Обратите внимание, что здесь речь идет не о стратегии, а о библиотеке шаблонов FMZ, которые можно искать в документации FMZ API и мы не будем обсуждать здесь.

Код формы:

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

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

  • $. Позмонтор. Эффект этой функции состоит в том, чтобы отслеживать изменения позиции обменных объектов в стратегии, а затем отправлять торговые сигналы боту, установленному в параметрах шаблона: order synchronous management system library (Single Server).
  • $$$$ Функция возвращает отслеживаемые синхронные данные.

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

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

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

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

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

Перед испытанием объясните конструкцию параметровOrder Synchronous Management System Library (Single Server)Стратегия: Я только что рассказал о том, как использовать интерфейсную функцию шаблона для обновления стратегии с функцией выполнения заказов. Вопрос о том, кому отправить, определяется параметрамиorder synchronous management system library (Single Server).

img

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

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

  • robotId Идентификатор бота;order synchronous management system (Synchronous Server)созданное владельцем синхронной учетной записи.

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

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

Тогда мы можем провести простой тест.

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

img

Бот " Order Synchronous Management System " (синхронный сервер) получил сигнал: Система синхронного управления заказами (синхронный сервер) сейчас не была полностью разработана нами, и мы можем использовать простой код, чтобы реализовать его, без торговли, только печать сигнала:

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

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 synchronous management system (Synchronous Server)Это лишь временный код, и мы сможем обсудить его дизайн в следующей статье.


Больше