В предыдущих статьях 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.система синхронного управления заказами (синхронный сервер)
Как только мы убедимся в наших требованиях, давайте начнем проектировать!
Обратите внимание, что здесь речь идет не о стратегии, а о библиотеке шаблонов 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)
Эта стратегия может использовать следующие функции.
Пример использования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)
.
Вы можете увидеть пять параметров, которые могут поддерживать максимум пять подталкиваний (если вам нужно увеличить число подталкиваний, вы можете расширить его самостоятельно); по умолчанию параметры являются пустой строкой, а именно не обрабатываются. В конфигурированном формате строки: label, robotId, accessKey, secretKey
маркировка Этикетка синхронного аккаунта, используемая для маркировки аккаунта; название этикеток может быть установлено случайным образом.
robotId
Идентификатор бота;order synchronous management system (Synchronous Server)
созданное владельцем синхронной учетной записи.
accessKey (ключ доступа) AccessKey FMZ расширенный API.
Секретный ключ Секретный ключ FMZ расширил API.
Тогда мы можем провести простой тест.
Операция бота библиотеки синхронной системы управления (один сервер):
Бот " 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)
}
}
Как видите, бот владельца синхронной учетной записи получил сообщение:ETH_USDT,swap,buy,1
- Да.
Таким образом, на следующем этапе мы можем контролировать заказы автоматически, в соответствии с торговой парой, кодом контракта, направлением торговли и объемом.
В настоящее время,order synchronous management system (Synchronous Server)
Это лишь временный код, и мы сможем обсудить его дизайн в следующей статье.