
В предыдущих статьях библиотеки FMZ мы разработали несколько стратегий синхронизации заказов и позиций.
Они предназначены для объединения справочного счета и счета синхронизации в одну стратегию для управления и синхронизации заказов и позиций. Сегодня мы попробуем другой дизайн. На основе мощного расширенного API-интерфейса количественной торговой платформы FMZ мы разработаем систему управления синхронизацией заказов.
Прежде всего нам нужны хорошие предложения и потребности. Две предыдущие стратегии синхронизации заказов и позиций имеют несколько очевидных болевых точек. Давайте обсудим их вместе:
Решение:
Используя расширенный API-интерфейс FMZ, владельцу учетной записи синхронизации (подписчику) необходимо только зарегистрировать количественную торговую платформу FMZ, а затем запустить стратегию (в системе, разработанной в этой статье:订单同步管理系统(Synchronous Server)Стратегия реального рынка). Затем предоставьте расширенный API-ключ FMZ (обратите внимание, не API-ключ учетной записи биржи) и идентификатор системы управления синхронизацией заказов (синхронный сервер) в реальном времени владельцу ссылочной учетной записи (лицу, которое размещает заказ). .
При ссылке на реальный заказ владельца аккаунта (того, у которого есть заказ) (в системе, разработанной в этой статье)订单同步管理系统类库(Single Server)) отправляет сигнал, реальный счет владельца синхронизированного счета получит торговый сигнал и автоматически разместит ордер.
订单同步管理系统类库(Single Server)Стратегия), позволяющая владельцу ссылочного аккаунта (лицу, принимающему заказ) напрямую встраивать эту библиотеку шаблонов в свою собственную стратегию для реализации функции синхронизации заказов и позиций.Итак, эта система состоит из 2 частей: 1. Библиотека классов системы управления синхронизацией заказов (один сервер) 2. Система синхронного управления заказами (синхронный сервер)
Теперь, когда требования ясны, давайте приступим к проектированию!
Обратите внимание, что это не стратегия. Это библиотека шаблонных классов 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)Параметры для настройки.

Вы видите, что имеется 5 параметров, поддерживающих до 5 push-запросов (при необходимости их можно расширить), а параметр по умолчанию представляет собой пустую строку, что означает, что он не обрабатывается. Формат строки конфигурации: label, robotId, accessKey, secretKey
label Метка синхронизированной учетной записи используется для обозначения определенной учетной записи, а имя можно задать по желанию.
robotId
Настоящий идентификатор, созданный владельцем учетной записи синхронизации订单同步管理系统(Synchronous Server)Идентификатор фактической транзакции.
accessKey Расширенный API-ключ доступа FMZ
secretKey Расширенный API-ключ FMZ secretKey
Далее мы можем провести простой тест.
Система управления синхронизацией заказа библиотеки классов (один сервер) работа реального диска:

Система управления синхронизацией заказов (Синхронный сервер) получила сигнал: Мы еще не закончили проектирование системы управления синхронизацией заказов (Synchronous Server). Давайте сначала реализуем ее с помощью простого кода, который не совершает транзакции, а только выводит сигналы:
Временный код системы управления синхронизацией заказов (Синхронный сервер):
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。
Таким образом, следующим шагом будет автоматическое выполнение заказа на основе торговой пары, кода контракта, направления торговли и количества, указанных в информации.
в настоящий момент订单同步管理系统(Synchronous Server)Это всего лишь временный код, мы продолжим изучать его дизайн в следующем выпуске.