रणनीति डिजाइन में शुरुआती लोगों के लिए, हेज रणनीति अभ्यास के लिए बहुत अच्छी है। यह लेख एक सरल लेकिन ठोस क्रिप्टोक्यूरेंसी स्पॉट हेज रणनीति को लागू करता है, जिससे शुरुआती लोगों को कुछ डिजाइन अनुभव सीखने की अनुमति मिलती है।
सबसे पहले, हमें यह सुनिश्चित करने की आवश्यकता है कि डिज़ाइन की जाने वाली रणनीति एक क्रिप्टोक्यूरेंसी स्पॉट हेज रणनीति है। हम सबसे सरल हेज डिजाइन करते हैं। हम केवल दो स्पॉट प्लेटफार्मों के बीच उच्चतम मूल्य के साथ मंच पर बेचते हैं, और मूल्य स्प्रेड अर्जित करने के लिए निम्नतम मूल्य के साथ मंच पर खरीदते हैं। जब उच्चतम मूल्य के साथ मंच उद्धरण मुद्रा प्रतीकों से भरा होता है (क्योंकि मूल्य अधिक है, सभी मुद्रा प्रतीकों को बेचा जाता है), या जब कम मूल्य के साथ मंच मुद्रा प्रतीकों से भरा होता है (क्योंकि मूल्य कम है, मुद्रा प्रतीकों को सभी परिसंपत्तियों द्वारा खरीदा जाता है), तो इसे हेज नहीं किया जा सकता है। इस समय, आप केवल मूल्य को हेज करने के लिए उलटने की प्रतीक्षा कर सकते हैं।
हेजिंग के दौरान ऑर्डर की कीमत और राशि के लिए, प्रत्येक प्लेटफ़ॉर्म में सटीकता सीमाएं हैं, और न्यूनतम ऑर्डर राशि पर भी एक सीमा है। न्यूनतम सीमा के अलावा, रणनीति को हेज के लिए अधिकतम ऑर्डर राशि पर भी विचार करने की आवश्यकता है। यदि ऑर्डर राशि बहुत बड़ी है, तो बाजार में इसके लिए पर्याप्त ऑर्डर मात्रा नहीं होगी। यह भी विचार करना आवश्यक है कि यदि दो प्लेटफार्मों में अलग-अलग उद्धरण मुद्राएं हैं तो विनिमय दर को कैसे परिवर्तित किया जाए। हेजिंग के दौरान हैंडलिंग शुल्क और ऑर्डर लेने वाले की फिसल सभी ट्रेडिंग लागत हैं। जब तक मूल्य अंतर होता है तब तक हेजिंग हमेशा नहीं होती है। इसलिए, हेजिंग मूल्य स्प्रेड का एक ट्रिगर मूल्य भी होता है। यदि यह एक निश्चित मूल्य स्प्रेड से कम है, तो हेजिंग नुकसान करेगा।
इसके आधार पर, रणनीति को कई मापदंडों के साथ डिजाइन करने की आवश्यकता हैः
hedgeDiffPrice
; जब स्प्रेड मूल्य से अधिक हो जाता है, तो एक हेज ट्रिगर किया जाएगा।minHedgeAmount
, एक हेज के लिए उपलब्ध न्यूनतम ऑर्डर राशि (प्रतीक राशि) है।maxHedgeAmount
, हेज के लिए उपलब्ध अधिकतम ऑर्डर राशि (प्रतीक राशि) ।pricePrecisionA
, प्लेटफ़ॉर्म ए के आदेश मूल्य की सटीकता (दशमलव अंक) ।amountPrecisionA
, प्लेटफ़ॉर्म ए के आदेश राशि की सटीकता (दशमलव अंक) ।pricePrecisionB
, प्लेटफ़ॉर्म बी के ऑर्डर मूल्य की सटीकता (दशमलव अंक) ।amountPrecisionB
, प्लेटफ़ॉर्म बी के आदेश राशि की सटीकता (दशमलव अंक) ।rateA
, पहली जोड़ी गई विनिमय वस्तु का विनिमय दर रूपांतरण; डिफ़ॉल्ट 1, रूपांतरण नहीं करने का संकेत देता है।rateB
, दूसरे जोड़े गए विनिमय वस्तु का विनिमय दर रूपांतरण; डिफ़ॉल्ट रूप से 1 है, जो रूपांतरण नहीं करने का संकेत देता है।हेज रणनीति को दो खातों की मुद्रा प्रतीक राशि को अपरिवर्तित रखने की आवश्यकता है (यानी, किसी भी दिशात्मक पदों को नहीं रखना, और तटस्थ बनाए रखना), इसलिए हमेशा संतुलन का पता लगाने के लिए रणनीति में संतुलन तर्क की आवश्यकता होती है। संतुलन की जांच करते समय, दो प्लेटफार्मों से परिसंपत्ति डेटा प्राप्त करना अपरिहार्य है। इसलिए, हमें उपयोग के लिए एक फ़ंक्शन लिखने की आवश्यकता है।
function updateAccs(arrEx) {
var ret = []
for (var i = 0 ; i < arrEx.length ; i++) {
var acc = arrEx[i].GetAccount()
if (!acc) {
return null
}
ret.push(acc)
}
return ret
}
आदेश देने के बाद, यदि कोई निष्पादित आदेश नहीं है, तो हमें इसे समय पर रद्द करने की आवश्यकता है, और आदेश को लंबित नहीं रखा जा सकता है। इस ऑपरेशन को बैलेंस मॉड्यूल और हेज लॉजिक दोनों में संसाधित करने की आवश्यकता है, इसलिए सभी आदेशों को रद्द करने के लिए एक फ़ंक्शन डिजाइन करना भी आवश्यक है।
function cancelAll() {
_.each(exchanges, function(ex) {
while (true) {
var orders = _C(ex.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
ex.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
}
})
}
मुद्रा प्रतीकों की मात्रा को संतुलित करते समय, हमें एक निश्चित मात्रा में एक निश्चित गहराई डेटा के साथ कीमत खोजने की जरूरत है, इसलिए हमें इसे संभालने के लिए इस तरह के एक फ़ंक्शन की आवश्यकता है।
function getDepthPrice(depth, side, amount) {
var arr = depth[side]
var sum = 0
var price = null
for (var i = 0 ; i < arr.length ; i++) {
var ele = arr[i]
sum += ele.Amount
if (sum >= amount) {
price = ele.Price
break
}
}
return price
}
फिर हमें विशिष्ट हेजिंग ऑर्डर ऑपरेशन को डिजाइन और लिखने की आवश्यकता है, जिसे एक साथ ऑर्डर देने के लिए डिज़ाइन किया जाना चाहिएः
function hedge(buyEx, sellEx, price, amount) {
var buyRoutine = buyEx.Go("Buy", price, amount)
var sellRoutine = sellEx.Go("Sell", price, amount)
Sleep(500)
buyRoutine.wait()
sellRoutine.wait()
}
अंत में, चलो संतुलन फ़ंक्शन के डिजाइन को पूरा करते हैं, जो थोड़ा अधिक जटिल है।
function keepBalance(initAccs, nowAccs, depths) {
var initSumStocks = 0
var nowSumStocks = 0
_.each(initAccs, function(acc) {
initSumStocks += acc.Stocks + acc.FrozenStocks
})
_.each(nowAccs, function(acc) {
nowSumStocks += acc.Stocks + acc.FrozenStocks
})
var diff = nowSumStocks - initSumStocks
// calculate currency spread
if (Math.abs(diff) > minHedgeAmount && initAccs.length == nowAccs.length && nowAccs.length == depths.length) {
var index = -1
var available = []
var side = diff > 0 ? "Bids" : "Asks"
for (var i = 0 ; i < nowAccs.length ; i++) {
var price = getDepthPrice(depths[i], side, Math.abs(diff))
if (side == "Bids" && nowAccs[i].Stocks > Math.abs(diff)) {
available.push(i)
} else if (price && nowAccs[i].Balance / price > Math.abs(diff)) {
available.push(i)
}
}
for (var i = 0 ; i < available.length ; i++) {
if (index == -1) {
index = available[i]
} else {
var priceIndex = getDepthPrice(depths[index], side, Math.abs(diff))
var priceI = getDepthPrice(depths[available[i]], side, Math.abs(diff))
if (side == "Bids" && priceIndex && priceI && priceI > priceIndex) {
index = available[i]
} else if (priceIndex && priceI && priceI < priceIndex) {
index = available[i]
}
}
}
if (index == -1) {
Log("cannot balance")
} else {
// balanced ordering
var price = getDepthPrice(depths[index], side, Math.abs(diff))
if (price) {
var tradeFunc = side == "Bids" ? exchanges[index].Sell : exchanges[index].Buy
tradeFunc(price, Math.abs(diff))
} else {
Log("invalid price", price)
}
}
return false
} else if (!(initAccs.length == nowAccs.length && nowAccs.length == depths.length)) {
Log("error:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
return true
} else {
return true
}
}
इन कार्यों को रणनीति की आवश्यकताओं के अनुसार डिजाइन किया गया है, और हम रणनीति के मुख्य कार्य को डिजाइन करना शुरू कर सकते हैं।
एफएमजेड पर, रणनीति कोmain
कार्य की शुरुआत में।main
समारोह, हम रणनीति के कुछ आरंभ करने की जरूरत है.
एक्सचेंज ऑब्जेक्ट का नाम रणनीति में कई संचालन के लिए विनिमय वस्तुओं का उपयोग करें, जैसे कि बाजार उद्धरण प्राप्त करना, आदेश देना, और इसी तरह, इसलिए हर बार एक लंबे नाम का उपयोग करना असुविधाजनक होगा, मेरी छोटी चाल इसके बजाय एक सरल संक्षिप्त नाम का उपयोग करना है, उदाहरण के लिएः
var exA = exchanges[0]
var exB = exchanges[1]
तो, यह बाद में कोड लिखने के लिए अधिक आरामदायक हो जाएगा.
विनिमय दर और सटीकता
// settings of precision and exchange rate
if (rateA != 1) {
// set exchange rate A
exA.SetRate(rateA)
Log("Platform A sets exchange rate:", rateA, "#FF0000")
}
if (rateB != 1) {
// set exchange rate B
exB.SetRate(rateB)
Log("Platform B sets exchange rate:", rateB, "#FF0000")
}
exA.SetPrecision(pricePrecisionA, amountPrecisionA)
exB.SetPrecision(pricePrecisionB, amountPrecisionB)
यदि विनिमय दर मापदंडों में से एक, अर्थात्rateA
औरrateB
, 1 पर सेट है (डिफ़ॉल्ट 1 है), यानी,rateA != 1
याrateB != 1
मतलब ट्रिगर नहीं हुआ है और विनिमय दर को परिवर्तित नहीं किया जा सकता है।
सभी दिनांक रीसेट करें
कभी कभी, यह सभी लॉग को हटाने के लिए आवश्यक है और डेटा रिकॉर्ड वैक्यूम जब रणनीति शुरू कर दिया है. आप एक रणनीति इंटरफ़ेस पैरामीटर डिजाइन कर सकते हैंisReset
, और फिर रणनीति के आरंभ भाग में रीसेट कोड डिजाइन, उदाहरण के लिएः
if (isReset) { // when "isReset" is true, reset the data
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("Reset all data", "#FF0000")
}
प्रारंभिक खाता डेटा पुनर्प्राप्त करें और चालू खाता डेटा अद्यतन करें
संतुलन का आकलन करने के लिए रणनीति को चालू खाते के साथ तुलना के लिए प्रारंभिक खाता परिसंपत्ति की स्थिति को लगातार रिकॉर्ड करने की आवश्यकता होती है।nowAccs
चालू खाते के आंकड़ों को रिकॉर्ड करने के लिए प्रयोग किया जाता है।updateAccs
फ़ंक्शन हम सिर्फ वर्तमान मंच के खाते डेटा प्राप्त करने के लिए डिजाइन किया है।initAccs
आरंभिक खाता स्थिति (जैसे मुद्रा प्रतीक A और B दोनों की राशि, बोली मुद्रा राशि आदि) रिकॉर्ड करने के लिए उपयोग किया जाता है।initAccs
, सबसे पहले उपयोग करें_G()
फ़ंक्शन को पुनर्स्थापित करने के लिए (_G फ़ंक्शन डेटा को लगातार रिकॉर्ड करेगा, और रिकॉर्ड किए गए डेटा को फिर से लौटा सकता है; विवरण के लिए एपीआई प्रलेखन पढ़ें:लिंक्स).
यदि आप डेटा क्वेरी नहीं कर सकते हैं, तो आवंटित करने और उपयोग करने के लिए चालू खाता जानकारी का उपयोग करें_G()
रिकॉर्ड करने के लिए फ़ंक्शन।
जैसे कि निम्न कोडः
var nowAccs = _C(updateAccs, exchanges)
var initAccs = _G("initAccs")
if (!initAccs) {
initAccs = nowAccs
_G("initAccs", initAccs)
}
मुख्य लूप में कोड रणनीति तर्क निष्पादन के प्रत्येक दौर की प्रक्रिया है, और नॉन-स्टॉप दोहराया निष्पादन रणनीति मुख्य लूप का निर्माण करता है। आइए मुख्य लूप में कार्यक्रम के प्रत्येक निष्पादन प्रवाह पर एक नज़र डालें।
बाजार के उद्धरण प्राप्त करें और वैधता का न्याय करें
var ts = new Date().getTime()
var depthARoutine = exA.Go("GetDepth")
var depthBRoutine = exB.Go("GetDepth")
var depthA = depthARoutine.wait()
var depthB = depthBRoutine.wait()
if (!depthA || !depthB || depthA.Asks.length == 0 || depthA.Bids.length == 0 || depthB.Asks.length == 0 || depthB.Bids.length == 0) {
Sleep(500)
continue
}
यहाँ आप देख सकते हैं कि समवर्ती समारोहexchange.Go
एफएमजेड प्लेटफॉर्म का उपयोग समवर्ती वस्तुओं को बनाने के लिए किया जाता हैdepthARoutine
औरdepthBRoutine
कि कॉलGetDepth()
जब इन दो समवर्ती वस्तुओं बनाया जाता है,GetDepth()
इंटरफ़ेस तुरंत बुलाया जाता है, और गहराई डेटा के लिए दोनों अनुरोध मंच को भेजा जाता है।
तो, कॉलwait()
वस्तु की विधिdepthARoutine
और वस्तुdepthBRoutine
गहराई के आंकड़े प्राप्त करने के लिए।
गहराई के आंकड़ों को प्राप्त करने के बाद, इसकी वैधता का आकलन करने के लिए गहराई के आंकड़ों की जांच करना आवश्यक है।continue
मुख्य लूप को फिर से निष्पादित करने के लिए कथन ट्रिगर किया जाता है.
प्रयोगprice spread
याspread ratio
?
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
मापदंडों के संदर्भ में, हम इस तरह के एक डिजाइन किया है. FMZ के मापदंडों किया जा सकता हैदिखावायाछुपानाएक पैरामीटर पर आधारित है, तो हम एक पैरामीटर तय करने के लिए उपयोग करने के लिए या नहीं कर सकते हैंprice spread
, याspread ratio
.
पैरामीटरdiffAsPercentage
रणनीति इंटरफेस के मापदंडों में जोड़ा गया है. अन्य दो मापदंडों, जो पैरामीटर के आधार पर दिखाया या छिपाया जाएगा के रूप में सेट कर रहे हैंःhedgeDiffPrice@!diffAsPercentage
जबdiffAsPercentage
झूठी है, यह दिखाया जाएगा।hedgeDiffPercentage@diffAsPercentage
जबdiffAsPercentage
सच है, यह प्रदर्शित किया जाएगा।
डिजाइन के बाद, हमने जांच की हैdiffAsPercentage
पैरामीटर, जो हेज ट्रिगर शर्त के रूप में स्प्रेड अनुपात का उपयोग करना है।diffAsPercentage
पैरामीटर की जाँच नहीं की जाती है, मूल्य स्प्रेड को हेज ट्रिगर की स्थिति के रूप में उपयोग किया जाता है।
न्यायाधीश हेज ट्रिगर
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A -> B market condition satisfied
var price = (depthA.Bids[0].Price + depthB.Asks[0].Price) / 2
var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance / price > minHedgeAmount) {
amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance / price, maxHedgeAmount)
Log("triggerA->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks) // prompt message
hedge(exB, exA, price, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
} else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPrice && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) { // B -> A market condition satisfied
var price = (depthB.Bids[0].Price + depthA.Asks[0].Price) / 2
var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance / price > minHedgeAmount) {
amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance / price, maxHedgeAmount)
Log("triggerB->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks) // prompt message
hedge(exA, exB, price, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
हेजिंग के लिए कई ट्रिगर शर्तें हैंः 1. सबसे पहले, हेज स्प्रेड को पूरा करें; जब बाजार स्प्रेड सेट स्प्रेड पैरामीटर को पूरा करता है, तब ही हेज संभव हो सकता है।
2.बाजार की हेजिंग राशि मापदंडों में निर्धारित न्यूनतम हेजिंग राशि को पूरा करनी चाहिए। क्योंकि विभिन्न प्लेटफार्मों के न्यूनतम ऑर्डर की राशि अलग-अलग होती है, इसलिए दोनों में से सबसे छोटी राशि ली जानी चाहिए।
3.बिक्री ऑपरेशन के साथ प्लेटफ़ॉर्म में संपत्ति बेचने के लिए पर्याप्त है, और खरीद ऑपरेशन के साथ प्लेटफ़ॉर्म में संपत्ति खरीदने के लिए पर्याप्त है। जब ये शर्तें पूरी हो जाती हैं, तो हेज द्वारा ऑर्डर रखने के लिए हेज फ़ंक्शन निष्पादित करें। मुख्य फ़ंक्शन से पहले, हम एक चर घोषित करते हैंisTrade
अग्रिम रूप से यह चिह्नित करने के लिए कि हेज होता है या नहीं। यहाँ, यदि हेज ट्रिगर किया जाता है, चर को सेट किया जाता हैtrue
. और वैश्विक चर रीसेट करेंlastKeepBalanceTS
0 पर (lastKeepBalanceTS का उपयोग अंतिम संतुलन ऑपरेशन के टाइमस्टैम्प को चिह्नित करने के लिए किया जाता है, और इसे 0 पर सेट करने से संतुलन ऑपरेशन तुरंत ट्रिगर हो जाएगा), और फिर सभी लंबित ऑर्डर रद्द करें।
संतुलन संचालन
if (ts - lastKeepBalanceTS > keepBalanceCyc * 1000) {
nowAccs = _C(updateAccs, exchanges)
var isBalance = keepBalance(initAccs, nowAccs, [depthA, depthB])
cancelAll()
if (isBalance) {
lastKeepBalanceTS = ts
if (isTrade) {
var nowBalance = _.reduce(nowAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
var initBalance = _.reduce(initAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
LogProfit(nowBalance - initBalance, nowBalance, initBalance, nowAccs)
isTrade = false
}
}
}
यह देखा जा सकता है कि संतुलन समारोह आवधिक रूप से निष्पादित किया जाता है, लेकिन अगरlastKeepBalanceTS
हेज ऑपरेशन के शुरू होने के बाद 0 पर रीसेट किया जाता है तो बैलेंस ऑपरेशन तुरंत शुरू हो जाएगा। बैलेंस सफल होने के बाद रिटर्न की गणना की जाएगी।
स्थिति पट्टी की जानकारी
LogStatus(_D(), "A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, " B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, " targetDiffPrice:", targetDiffPrice, "\n",
"currentA,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n",
"currentB,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n",
"initialA,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n",
"initialB,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
स्थिति पट्टी को विशेष रूप से जटिल बनाने के लिए डिज़ाइन नहीं किया गया है। यह वर्तमान समय, प्लेटफ़ॉर्म ए से प्लेटफ़ॉर्म बी तक मूल्य स्प्रेड के साथ-साथ प्लेटफ़ॉर्म बी से ए तक मूल्य स्प्रेड प्रदर्शित करता है; यह वर्तमान हेज लक्ष्य स्प्रेड, प्लेटफ़ॉर्म ए के खाता परिसंपत्ति डेटा और प्लेटफ़ॉर्म बी के खाता परिसंपत्ति डेटा भी प्रदर्शित करता है।
मापदंडों के संदर्भ में, हमने विनिमय दर मूल्य के रूपांतरण के मापदंड को डिजाइन किया है, और हमने विनिमय दर रूपांतरण को भी डिजाइन किया हैmain
यह ध्यान दिया जाना चाहिए किSetRate
विनिमय दर रूपांतरण फ़ंक्शन को पहले निष्पादित करने की आवश्यकता है।
कार्य के लिए दो पहलुओं को प्रभावित करेगाः
उदाहरण के लिए, वर्तमान व्यापारिक जोड़ी हैBTC_USDT
, मूल्य इकाई हैUSDT
, और खाता परिसंपत्तियों में उपलब्ध बोली मुद्रा भीUSDT
. अगर मैं CNY में परिसंपत्तियों के मूल्य परिवर्तित करना चाहते हैं, सेटexchange.SetRate(6.8)
कोड में सभी कार्यों द्वारा प्राप्त डेटा को परिवर्तित करने के लिएexchange
वस्तु, और फिर CNY में परिवर्तित करें।
किस उद्धरण मुद्रा में परिवर्तित करने के लिए, आयातवर्तमान बोली मुद्रा से लक्ष्य बोली मुद्रा में विनिमय दरमेंSetRate
function.
पूर्ण रणनीति:विभिन्न उद्धरण मुद्राओं की स्पॉट हेज रणनीति (शिक्षण)