एफएमजेड डाइजेस्ट पर पिछले लेखों में, हमने कई क्रम और स्थिति सिंक्रोनस रणनीतियों को डिजाइन किया है।
इन डिजाइनों में संदर्भ खाते और सिंक्रोनस खाते को एक ही रणनीति में लिया जाता है ताकि आदेशों और पदों के सिंक्रनाइज़ेशन को महसूस करने के लिए प्रबंधित किया जा सके। आज, हम एक अलग डिजाइन की कोशिश कर सकते हैं; एफएमजेड के शक्तिशाली विस्तारित एपीआई इंटरफ़ेस के आधार पर, यहां हम एक ऑर्डर सिंक्रोनस प्रबंधन प्रणाली डिजाइन करते हैं।
सबसे पहले, हमें कुछ अच्छे सुझावों और आवश्यकताओं की आवश्यकता है। उपरोक्त दो पिछले आदेशों और पदों के सिंक्रनाइज़ेशन रणनीतियों में कई स्पष्ट नुकसान हैं। आइए उन पर एक साथ चर्चा करेंः
1. रणनीति बॉट सिंक्रनाइज़ेशन को लागू करने वाले उपयोगकर्ताओं के पास संदर्भ खाता प्लेटफॉर्म की एपीआई कुंजी और सिंक्रनाइज़ेशन खाते की एपीआई कुंजी होनी चाहिए। उपयोग के परिदृश्य के लिए, समस्या यह हैः आपके अन्य प्लेटफ़ॉर्म खातों के लिए आपके अपने खातों में से एक का पालन करना ठीक है। लेकिन यह उस परिदृश्य के लिए कष्टप्रद हो सकता है जहां संदर्भ खाते और सिंक्रनाइज़ेशन खाते का एक ही मालिक नहीं है। सिंक्रनाइज़ेशन खाते का मालिक कभी-कभी सुरक्षा कारणों से अपने प्लेटफ़ॉर्म खाते की एपीआई कुंजी प्रदान करने के इच्छुक नहीं होता है। लेकिन एपीआई कुंजी प्रदान किए बिना सिंक्रनाइज़ेशन ट्रेडिंग के लिए ऑर्डर कैसे करें?
समाधान:
एफएमजेड विस्तारित एपीआई का उपयोग करें, सिंक्रनाइज़ेशन खाते के मालिक (ऑर्डर पर्यवेक्षक) को केवल एफएमजेड क्वांट ट्रेडिंग प्लेटफॉर्म को पंजीकृत करने की आवश्यकता है, और फिर एक रणनीति चलाएं (इस लेख में डिज़ाइन की गई प्रणाली मेंःOrder Synchronous Management System (Synchronous Server)
फिर, एफएमजेड की विस्तारित एपीआई कुंजी (ध्यान दें कि यह प्लेटफ़ॉर्म खाते की एपीआई कुंजी नहीं है) और ऑर्डर सिंक्रनाइज़ेशन प्रबंधन प्रणाली (एकीकृत सर्वर) की बॉट आईडी संदर्भ खाते के मालिक (ऑर्डर स्वामी) को प्रदान की जाएगी।
जब संदर्भ खाते के मालिक (ऑर्डर के मालिक) का बॉट (Order Synchronous Management System Library (Single Server)
इस लेख में डिजाइन की गई प्रणाली में) एक संकेत भेजता है, सिंक्रनाइज़ेशन खाते के मालिक का बॉट ट्रेडिंग संकेत प्राप्त करेगा। आदेश स्वचालित रूप से बाद में रखा जाएगा।
2. कई डेवलपर्स के पास बेहतर रणनीतियाँ हैं और ऊपर वर्णित दो पिछले आदेश और स्थिति सिंक्रनाइज़ेशन रणनीतियों का उपयोग नहीं कर सकते हैं। क्योंकि इसके लिए इन सिंक्रनाइज़ेशन रणनीतियों के साथ अपनी रणनीतियों को मर्ज करने की आवश्यकता है, और उनकी रणनीतियों को काफी संशोधित करने की आवश्यकता हो सकती है, जो समय लेने वाली और श्रम-गहन है। क्या आपके कुछ परिपक्व रणनीतियों को सीधे ऑर्डर सिंक्रनाइज़ेशन फ़ंक्शन वाले लोगों के लिए अपग्रेड करने का एक अच्छा तरीका है?
समाधान:
आप एक आदेश सिंक्रोनस टेम्पलेट लाइब्रेरी डिजाइन कर सकते हैंOrder Synchronous Management System Library (Single Server)
लेख में डिजाइन की गई प्रणाली में रणनीति), ताकि संदर्भ खाते के मालिक (ऑर्डर के मालिक) सीधे इस टेम्पलेट लाइब्रेरी को अपनी रणनीति में क्रम और स्थिति सिंक्रनाइज़ेशन प्राप्त करने के लिए सम्मिलित कर सकें।
3.एक अतिरिक्त बॉट को कम करें अंतिम दोष यह है कि यदि आप ऊपर वर्णित दो पूर्ववर्ती आदेशों और स्थिति सिंक्रनाइज़ेशन रणनीतियों का उपयोग करते हैं, तो बॉट निगरानी के लिए संदर्भ खाते (आदेशों के साथ खाता) की एक अतिरिक्त स्थिति खोलना आवश्यक है। समाधान: फ़ंक्शन को संदर्भ खाता रणनीति में एम्बेड करने के लिए टेम्पलेट लाइब्रेरी का प्रयोग करें.
अतः इस प्रणाली में दो भाग होते हैंः 1.ऑर्डर सिंक्रोनस मैनेजमेंट सिस्टम लाइब्रेरी (एकल सर्वर) 2.ऑर्डर सिंक्रोनस मैनेजमेंट सिस्टम (सिंक्रोनस सर्वर)
एक बार जब हम अपनी मांगों को सुनिश्चित कर लेते हैं, तो चलिए डिजाइन करना शुरू करते हैं!
ध्यान दें कि यहाँ यह एक रणनीति नहीं है, लेकिन एक FMZ टेम्पलेट पुस्तकालय है, जो FMZ एपीआई प्रलेखन में खोज किया जा सकता है और हम यहाँ चर्चा नहीं करेंगे।
टेम्पलेट कोडः
// 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
अपनी एक रणनीति का कार्य।
परीक्षण कोड को परीक्षण के लिए ओकेएक्स सिमुलेटेड बॉट का उपयोग करने के लिए लिखा गया है, और ओकेएक्स सिमुलेटेड बॉट की एपीआई कुंजी को एफएमजेड पर एक संदर्भ खाते (ऑर्डर के साथ) के रूप में कॉन्फ़िगर करने की आवश्यकता है, और मुख्य फ़ंक्शन सिमुलेटेड बॉट पर स्विच करना शुरू कर देता है। फिर ट्रेडिंग जोड़ी को ETH_USDT पर सेट करें, और कॉन्ट्रैक्ट को स्वैप करने के लिए सेट करें। फिर एक जबकि लूप दर्ज करें। लूप में, रणनीति ट्रेडों के ट्रिगर का अनुकरण करने के लिए हर 3 मिनट में एक ऑर्डर रखा जाता है।$.PosMonitor(0, "ETH_USDT", "swap")
जबकि लूप में बुलाया जाता है, और बुलाया फ़ंक्शन का पहला पैरामीटर 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)
.
आप पांच मापदंडों को देख सकते हैं, जो अधिकतम पांच धक्का का समर्थन कर सकते हैं (यदि आपको धक्का संख्या बढ़ाने की आवश्यकता है, तो आप इसे स्वयं बढ़ा सकते हैं); मापदंडों का डिफ़ॉल्ट एक खाली स्ट्रिंग है, अर्थात् संसाधित नहीं है। विन्यस्त स्ट्रिंग प्रारूप मेंः लेबल, robotId, accessKey, secretKey
लेबल सिंक्रोनस खाते का लेबल, जिसका उपयोग किसी खाते को लेबल करने के लिए किया जाता है; लेबल का नाम यादृच्छिक रूप से सेट किया जा सकता है।
robotId
बॉट आईडी; बॉट आईडीorder synchronous management system (Synchronous Server)
सिंक्रोनस खाते के मालिक द्वारा बनाया गया।
accessKey एफएमजेड विस्तारित एपीआई की एक्सेसकी।
गुप्त कुंजी FMZ विस्तारित एपीआई की गुप्त कुंजी।
फिर, हम एक सरल परीक्षण कर सकते हैं।
ऑर्डर सिंक्रोनस मैनेजमेंट सिस्टम लाइब्रेरी (एकल सर्वर) बॉट ऑपरेशनः
ऑर्डर सिंक्रोनस मैनेजमेंट सिस्टम (सिंक्रोनस सर्वर) बॉट ने संकेत प्राप्त कियाः ऑर्डर सिंक्रोनस मैनेजमेंट सिस्टम (सिंक्रोनस सर्वर) अब हमारे द्वारा पूरी तरह से डिजाइन नहीं किया गया है, और हम एक सरल कोड का उपयोग कर सकते हैं इसे महसूस करने के लिए, व्यापार के बिना, केवल प्रिंट सिग्नलः
ऑर्डर सिंक्रोनस मैनेजमेंट सिस्टम (सिंक्रोनस सर्वर) अस्थायी कोडः
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)
केवल अस्थायी कोड है, और हम इसके डिजाइन पर आगे चर्चा कर सकते हैं अगले लेख में।