लंबे समय से, क्रिप्टो मुद्रा विनिमय के एपीआई इंटरफ़ेस की डेटा देरी समस्या ने मुझे हमेशा परेशान किया है। मुझे इससे निपटने का एक उपयुक्त तरीका नहीं मिला है। मैं इस समस्या के दृश्य को पुनः पेश करूंगा।
आमतौर पर कॉन्ट्रैक्ट एक्सचेंज द्वारा प्रदान किया जाने वाला मार्केट ऑर्डर वास्तव में प्रतिपक्ष मूल्य होता है, इसलिए कभी-कभी तथाकथित
समस्या इस स्थिति की जानकारी में निहित है. आदेश बंद है, तो डेटा विनिमय स्थिति सूचना इंटरफ़ेस द्वारा लौटाया (यानी विनिमय इंटरफ़ेस है कि नीचे की परत वास्तव में पहुँचता है जब हम कॉलexchange.GetPosition
) में नव-खुली स्थिति की जानकारी होनी चाहिए, लेकिन यदि एक्सचेंज द्वारा लौटाए गए डेटा पुराने डेटा हैं, अर्थात लेनदेन पूरा होने से पहले रखे गए ऑर्डर की स्थिति की जानकारी, तो इससे समस्या होगी।
ट्रेडिंग तर्क यह मान सकता है कि ऑर्डर को पूरा नहीं किया गया है और ऑर्डर देना जारी रखता है। हालांकि, एक्सचेंज के ऑर्डर प्लेसमेंट इंटरफ़ेस में देरी नहीं होती है, लेकिन लेनदेन तेज़ होता है, और ऑर्डर निष्पादित होता है। इससे एक गंभीर परिणाम होगा कि रणनीति एक स्थिति खोलने के ऑपरेशन को ट्रिगर करते समय बार-बार ऑर्डर देगी।
इस समस्या के कारण, मैंने एक लंबी स्थिति को भरने की रणनीति को पागल देखा है, सौभाग्य से, उस समय बाजार बढ़ गया था, और फ्लोटिंग लाभ एक बार 10BTC से अधिक था। सौभाग्य से, बाजार आसमान छू गया है। यदि यह एक डुबकी है, तो अंत की कल्पना की जा सकती है।
ऑर्डर प्लेसमेंट के तर्क को केवल एक ऑर्डर देने की रणनीति के लिए डिज़ाइन करना संभव है। ऑर्डर प्लेसमेंट की कीमत उस समय प्रतिद्वंद्वी की कीमत के मूल्य अंतर के लिए एक बड़ी फिसलन है, और प्रतिद्वंद्वी के आदेशों की एक निश्चित गहराई निष्पादित की जा सकती है। इसका लाभ यह है कि केवल एक ऑर्डर रखा जाता है, और इसे स्थिति की जानकारी के आधार पर न्याय नहीं किया जाता है। इससे बार-बार ऑर्डर देने की समस्या से बचा जा सकता है, लेकिन कभी-कभी जब कीमत अपेक्षाकृत बड़ी होती है, तो ऑर्डर एक्सचेंज की मूल्य सीमा तंत्र को ट्रिगर करेगा, और इससे हो सकता है कि बड़ा फिसलन ऑर्डर अभी भी पूरा नहीं हुआ है, और व्यापारिक अवसर खो गया है।
एक्सचेंज के
हम अभी भी पिछले ट्रेडिंग लॉजिक का उपयोग करते हैं और एक सीमा ऑर्डर देते हैं, लेकिन हम स्थिति डेटा की देरी के कारण होने वाली समस्या को हल करने की कोशिश करने के लिए ट्रेडिंग लॉजिक में कुछ डिटेक्शन जोड़ते हैं। ऑर्डर दिए जाने के बाद, यदि ऑर्डर रद्द नहीं किया जाता है, तो यह लंबित ऑर्डर की सूची में सीधे गायब हो जाता है (लंबित ऑर्डर की सूची दो संभावित तरीकों से गायब हो जाती हैः 1 ऑर्डर वापस लें, 2 निष्पादित), ऐसी स्थिति का पता लगाएं और ऑर्डर राशि फिर से रखें। अंतिम ऑर्डर की राशि समान है। इस समय, इस बात पर ध्यान देना आवश्यक है कि क्या स्थिति डेटा में देरी हुई है। स्थिति की जानकारी को फिर से प्राप्त करने के लिए प्रोग्राम को प्रतीक्षा लॉजिक में प्रवेश करने दें। आप ट्रिगरिंग प्रतीक्षा की संख्या को अनुकूलित करना और बढ़ाना भी जारी रख सकते हैं। यदि यह एक निश्चित संख्या से अधिक बार होता है, तो स्थिति इंटरफ़ेस डेटा में देरी होती है। समस्या गंभीर है, लेनदेन लॉजिक को समाप्त करने दें।
// Parameter
/*
var MinAmount = 1
var SlidePrice = 5
var Interval = 500
*/
function GetPosition(e, contractType, direction) {
e.SetContractType(contractType)
var positions = _C(e.GetPosition);
for (var i = 0; i < positions.length; i++) {
if (positions[i].ContractType == contractType && positions[i].Type == direction) {
return positions[i]
}
}
return null
}
function Open(e, contractType, direction, opAmount) {
var initPosition = GetPosition(e, contractType, direction);
var isFirst = true;
var initAmount = initPosition ? initPosition.Amount : 0;
var nowPosition = initPosition;
var directBreak = false
var preNeedOpen = 0
var timeoutCount = 0
while (true) {
var ticker = _C(e.GetTicker)
var needOpen = opAmount;
if (isFirst) {
isFirst = false;
} else {
nowPosition = GetPosition(e, contractType, direction);
if (nowPosition) {
needOpen = opAmount - (nowPosition.Amount - initAmount);
}
// Detect directBreak and the position has not changed
if (preNeedOpen == needOpen && directBreak) {
Log("Suspected position data is delayed, wait 30 seconds", "#FF0000")
Sleep(30000)
nowPosition = GetPosition(e, contractType, direction);
if (nowPosition) {
needOpen = opAmount - (nowPosition.Amount - initAmount);
}
/*
timeoutCount++
if (timeoutCount > 10) {
Log("Suspected position delay for 10 consecutive times, placing order fails!", "#FF0000")
break
}
*/
} else {
timeoutCount = 0
}
}
if (needOpen < MinAmount) {
break;
}
var amount = needOpen;
preNeedOpen = needOpen
e.SetDirection(direction == PD_LONG ? "buy" : "sell");
var orderId;
if (direction == PD_LONG) {
orderId = e.Buy(ticker.Sell + SlidePrice, amount, "Open long position", contractType, ticker);
} else {
orderId = e.Sell(ticker.Buy - SlidePrice, amount, "Open short position", contractType, ticker);
}
directBreak = false
var n = 0
while (true) {
Sleep(Interval);
var orders = _C(e.GetOrders);
if (orders.length == 0) {
if (n == 0) {
directBreak = true
}
break;
}
for (var j = 0; j < orders.length; j++) {
e.CancelOrder(orders[j].Id);
if (j < (orders.length - 1)) {
Sleep(Interval);
}
}
n++
}
}
var ret = {
price: 0,
amount: 0,
position: nowPosition
};
if (!nowPosition) {
return ret;
}
if (!initPosition) {
ret.price = nowPosition.Price;
ret.amount = nowPosition.Amount;
} else {
ret.amount = nowPosition.Amount - initPosition.Amount;
ret.price = _N(((nowPosition.Price * nowPosition.Amount) - (initPosition.Price * initPosition.Amount)) / ret.amount);
}
return ret;
}
function Cover(e, contractType, opAmount, direction) {
var initPosition = null;
var position = null;
var isFirst = true;
while (true) {
while (true) {
Sleep(Interval);
var orders = _C(e.GetOrders);
if (orders.length == 0) {
break;
}
for (var j = 0; j < orders.length; j++) {
e.CancelOrder(orders[j].Id);
if (j < (orders.length - 1)) {
Sleep(Interval);
}
}
}
position = GetPosition(e, contractType, direction)
if (!position) {
break
}
if (isFirst == true) {
initPosition = position;
opAmount = Math.min(opAmount, initPosition.Amount)
isFirst = false;
}
var amount = opAmount - (initPosition.Amount - position.Amount)
if (amount <= 0) {
break
}
var ticker = _C(exchange.GetTicker)
if (position.Type == PD_LONG) {
e.SetDirection("closebuy");
e.Sell(ticker.Buy - SlidePrice, amount, "Close long position", contractType, ticker);
} else if (position.Type == PD_SHORT) {
e.SetDirection("closesell");
e.Buy(ticker.Sell + SlidePrice, amount, "Close short position", contractType, ticker);
}
Sleep(Interval)
}
return position
}
$.OpenLong = function(e, contractType, amount) {
if (typeof(e) == "string") {
amount = contractType
contractType = e
e = exchange
}
return Open(e, contractType, PD_LONG, amount);
}
$.OpenShort = function(e, contractType, amount) {
if (typeof(e) == "string") {
amount = contractType
contractType = e
e = exchange
}
return Open(e, contractType, PD_SHORT, amount);
};
$.CoverLong = function(e, contractType, amount) {
if (typeof(e) == "string") {
amount = contractType
contractType = e
e = exchange
}
return Cover(e, contractType, amount, PD_LONG);
};
$.CoverShort = function(e, contractType, amount) {
if (typeof(e) == "string") {
amount = contractType
contractType = e
e = exchange
}
return Cover(e, contractType, amount, PD_SHORT);
};
function main() {
Log(exchange.GetPosition())
var info = $.OpenLong(exchange, "quarter", 100)
Log(info, "#FF0000")
Log(exchange.GetPosition())
info = $.CoverLong(exchange, "quarter", 30)
Log(exchange.GetPosition())
Log(info, "#FF0000")
info = $.CoverLong(exchange, "quarter", 80)
Log(exchange.GetPosition())
Log(info, "#FF0000")
}
टेम्पलेट का पताःhttps://www.fmz.com/strategy/203258
टेम्पलेट इंटरफेस को कॉल करने का तरीका बस की तरह है$.OpenLong
और$.CoverLong
मेंmain
उपरोक्त कार्य।
टेम्पलेट एक बीटा संस्करण है, किसी भी सुझाव का स्वागत है, मैं स्थिति डेटा में देरी की समस्या से निपटने के लिए अनुकूलित करने के लिए जारी रहेगा.