FMZ 다이제스트의 이전 기사에서 우리는 여러 순서와 위치 동기 전략을 설계했습니다.
이 설계는 참조 계정과 동기 계정을 동일한 전략으로 받아서 주문과 포지션의 동기화를 실현하기 위해 관리 할 수 있습니다. 오늘날, 우리는 다른 디자인을 시도 할 수 있습니다. FMZ의 강력한 확장 API 인터페이스를 기반으로, 여기 우리는 주문 동기 관리 시스템을 설계합니다.
우선, 우리는 몇 가지 좋은 제안과 요구 사항이 필요합니다. 위의 두 개의 이전 명령과 위치 동기화 전략에는 몇 가지 명백한 단점이 있습니다. 함께 논의하자:
1.전략 봇 동기화를 구현하는 사용자는 참조 계정 플랫폼의 API 키와 동기화 계정의 API 키를 가지고 있어야합니다. 사용 시나리오의 경우, 문제는: 다른 플랫폼 계정이 자신의 계정 중 하나를 따르는 것이 좋습니다. 그러나 참조 계정과 동기화 계정이 동일한 소유자가없는 시나리오에 문제가 될 수 있습니다. 동기화 계정 소유자는 보안상의 이유로 때때로 플랫폼 계정의 API 키를 제공하기를 원하지 않습니다. 그러나 API 키를 제공하지 않고 동시 거래에 대한 주문을 어떻게 할 수 있습니까?
해결책:
FMZ 확장 API를 사용하면 동기화 계정 소유자 (오더 감독자) 는 FMZ 퀀트 거래 플랫폼을 등록하고 전략을 실행해야합니다.Order Synchronous Management System (Synchronous Server)
그 다음, FMZ의 확장 된 API 키 (플랫폼 계정의 API 키가 아니라는 점에 유의하십시오) 와 주문 동기화 관리 시스템 (동시 서버) 의 bot ID는 참조 계정 소유자 (오더 소유자) 에 제공됩니다.
참조 계정 소유자의 (계정 소유자)Order Synchronous Management System Library (Single Server)
이 기사에서 설계된 시스템에서) 신호를 보내면 동기화 계정 소유자의 봇이 거래 신호를 수신합니다. 주문은 나중에 자동으로 배치됩니다.
2.많은 개발자는 더 나은 전략을 가지고 있으며 위에서 설명한 이전 두 가지 순서 및 위치 동기화 전략을 사용할 수 없습니다. 왜냐하면 자신의 전략을 이러한 동기화 전략과 결합해야하고 전략이 크게 수정되어야 할 수 있기 때문에 시간이 많이 걸리고 노동이 많이 필요합니다. 성숙한 전략 중 일부를 순서 동기화 기능으로 직접 업그레이드 할 수있는 좋은 방법이 있습니까?
해결책:
당신은 순서 동기 템플릿 라이브러리를 설계할 수 있습니다 (Order Synchronous Management System Library (Single Server)
기사에 설계된 시스템에서 전략), 그래서 참조 계정 소유자 (명령 소유자) 는 순서와 위치 동기화를 달성하기 위해 자신의 전략에 직접 이 템플릿 라이브러리를 삽입 할 수 있습니다.
3.더 많은 로봇을 줄이세요. 마지막 단점은 위에서 설명한 두 가지 이전 명령과 위치 동기화 전략을 사용하는 경우 보트 모니터링을 위해 참조 계정의 추가 위치 (명령과 계정) 를 여는 것이 필요하다는 것입니다. 해결책: 템플릿 라이브러리를 사용하여 참조 계정 전략에 함수를 삽입합니다.
따라서 시스템은 두 부분으로 구성됩니다. 1.order 동기 관리 시스템 라이브러리 (Single Server) 주문 동기 관리 시스템 (동시 서버)
일단 우리의 요구사항을 확인하면, 디자인을 시작합시다!
여기 전략이 아니라 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
순서 동기 관리 시스템 라이브러리 (Single Server):
// 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 시뮬레이션 봇을 사용하도록 작성되었으며, OKEX 시뮬레이션 봇의 API KEY는 FMZ에서 참조 계정 (오더와 함께) 으로 구성되어야하며, 주요 기능은 시뮬레이션 봇으로 전환되기 시작합니다. 그 다음 거래 쌍을 ETH_USDT로 설정하고 계약을 교환하도록 설정합니다. 그 다음 while 루프를 입력합니다. 루프에서 전략 거래의 트리거를 시뮬레이션하기 위해 3 분마다 주문이 배치됩니다.$.PosMonitor(0, "ETH_USDT", "swap")
while 루프에서 호출되고 호출 함수의 첫 번째 매개 변수는 0이며, 이는 교환 객체 교환[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)
.
당신은 최대 5 개의 푸시를 지원 할 수있는 다섯 개의 매개 변수를 볼 수 있습니다 (두려움 번호를 증가시킬 필요가 있다면, 당신은 그것을 스스로 확장 할 수 있습니다); 매개 변수의 기본 설정은 처리되지 않은 빈 문자열입니다. 구성된 문자열 형식에서: 레이블, robotId, accessKey, secretKey
라벨 동기 계정의 라벨, 계정을 라벨하는 데 사용된다. 라벨 이름은 무작위로 설정될 수 있다.
로봇
봇 아이디order synchronous management system (Synchronous Server)
동시 계정 소유자가 만든 것입니다.
accessKey FMZ 확장 API의 AccessKey.
비밀 키 FMZ의 비밀 키는 확장된 API입니다.
그러면 간단한 테스트를 할 수 있습니다.
명령 동기 관리 시스템 라이브러리 (단독 서버) 봇 동작:
오더 동기 관리 시스템 (동시 서버) 봇은 신호를 받았습니다: 주문 동기 관리 시스템 (동시 서버) 지금은 우리가 완전히 설계되지 않았으며, 우리는 간단한 코드를 사용하여 그것을 실현 할 수 있습니다, 거래 없이, 단지 신호 인쇄:
주문 동기 관리 시스템 (동시 서버) 임시 코드:
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)
단지 임시적인 코드입니다. 다음 기사에서 그 설계에 대해 더 자세히 설명할 수 있습니다.