
ایک طویل عرصے سے، ڈیجیٹل کرنسی ایکسچینج پوزیشن API انٹرفیس کے ڈیٹا میں تاخیر کا مسئلہ ہمیشہ مجھے پریشان کرتا رہا ہے۔ مجھے ابھی تک کوئی مناسب حل نہیں ملا ہے، لہذا میں اس مسئلے کو دوبارہ پیش کروں گا۔ عام طور پر کنٹریکٹ ایکسچینج کی طرف سے فراہم کردہ مارکیٹ آرڈر دراصل کاؤنٹر پارٹی قیمت ہے، لہذا بعض اوقات اس نام نہاد “مارکیٹ آرڈر” کو استعمال کرنا ناقابل اعتبار ہے۔ لہذا، جب ہم ڈیجیٹل کرنسی فیوچر ٹریڈنگ کی حکمت عملی لکھتے ہیں، تو ہم میں سے زیادہ تر حد کے آرڈرز کا استعمال کرتے ہیں۔ ہر آرڈر دینے کے بعد، ہمیں یہ دیکھنے کے لیے پوزیشن کو چیک کرنے کی ضرورت ہے کہ آیا آرڈر پر عمل ہوا ہے اور کیا متعلقہ پوزیشن پر فائز ہے۔ مسئلہ اس پوزیشن کی معلومات میں ہے اگر آرڈر پر عمل کیا جاتا ہے، تو ایکسچینج پوزیشن انفارمیشن انٹرفیس (یعنی ایکسچینج انٹرفیس تک رسائی حاصل ہوتی ہے جب ہم ایکسچینج کو کہتے ہیں) میں نئی کھلی ہوئی پوزیشن کی معلومات شامل ہونی چاہیے۔ ایکسچینج کی طرف سے واپس کیا گیا ڈیٹا پرانا ڈیٹا ہے، یعنی پوزیشن کی معلومات اس سے پہلے کہ آرڈر پر عمل درآمد ہو، پھر کوئی مسئلہ ہو گا۔ تجارتی منطق یہ سوچ سکتی ہے کہ آرڈر پر عمل نہیں ہوا ہے اور آرڈر دینا جاری رکھے گا۔ تاہم، ایکسچینج کے آرڈر پلیسمنٹ انٹرفیس میں کسی تاخیر کا سامنا نہیں ہوتا ہے، اس کے بجائے، لین دین بہت تیزی سے مکمل ہو جاتے ہیں، اور جیسے ہی وہ رکھے جاتے ہیں۔ اس کے نتیجے میں ایک سنگین نتیجہ نکلے گا کہ جب کوئی اوپننگ آپریشن شروع کیا جائے گا تو حکمت عملی بار بار آرڈر دے گی۔
اس مسئلے کی وجہ سے، میں نے ایک ایسی حکمت عملی دیکھی ہے جس نے ایک پاگل مکمل لمبی پوزیشن کھولی ہے، خوش قسمتی سے، اس وقت مارکیٹ عروج پر تھی اور فلوٹنگ منافع ایک بار 10BTC سے تجاوز کر گیا تھا۔ خوش قسمتی سے، مارکیٹ عروج پر ہے، اگر یہ گرتا تو نتیجہ متوقع ہوتا۔
حل 1 حکمت عملی کی آرڈر منطق کو صرف ایک آرڈر دینے کے لیے ڈیزائن کیا جا سکتا ہے، اور آرڈر کی قیمت اس وقت مخالف کی قیمت کے علاوہ ایک بڑی پھسلن ہوتی ہے، تاکہ مخالف کے آرڈرز کو ایک خاص گہرائی میں لے جا سکے۔ ایسا کرنے کا فائدہ یہ ہے کہ آپ صرف ایک بار آرڈر دیتے ہیں اور یہ پوزیشن کی معلومات پر مبنی نہیں ہوتا ہے۔ یہ ڈپلیکیٹ آرڈرز کے مسئلے سے بچ سکتا ہے، لیکن بعض اوقات جب قیمت بہت زیادہ بدل جاتی ہے تو آرڈر دینا ایکسچینج کی قیمت کی حد کے طریقہ کار کو متحرک کر سکتا ہے، اور یہ ممکن ہے کہ بڑی پھسلن کے باوجود بھی آرڈر پر عمل نہ کیا جائے، اس طرح موقع ضائع ہو جاتا ہے۔ .
حل 2 ایکسچینج کے مارکیٹ آرڈر فنکشن کا استعمال کریں اور FMZ پر پاس -1 کو قیمت کے طور پر استعمال کریں، جو کہ فی الحال، OKEX فیوچر انٹرفیس کو حقیقی مارکیٹ آرڈرز کو سپورٹ کرنے کے لیے اپ گریڈ کیا گیا ہے۔
حل 3 ہم اب بھی پچھلی ٹریڈنگ منطق کا استعمال کرتے ہیں اور حد کے آرڈرز کا استعمال کرتے ہوئے آرڈر دیتے ہیں، لیکن پوزیشن ڈیٹا میں تاخیر کی وجہ سے پیدا ہونے والے مسئلے کو حل کرنے کی کوشش کرنے کے لیے ہم تجارتی منطق میں کچھ کھوج شامل کرتے ہیں۔ چیک کریں کہ آیا آرڈر دینے کے بعد منسوخ کیے بغیر آرڈر زیر التواء آرڈر کی فہرست سے غائب ہو جاتا ہے (پینڈنگ آرڈر کی فہرست سے غائب ہونے کے دو امکانات ہیں: 1 منسوخی اور 2 تکمیل) اور آرڈر کی مقدار اور آرڈر حجم پچھلی بار کے برابر ہے، آپ کو اس بات پر توجہ دینی چاہیے کہ آیا پروگرام کو انتظار کی منطق میں داخل ہونے دیں اور آپ اپنی تعداد میں اضافہ بھی جاری رکھ سکتے ہیں۔ اگر یہ ایک مخصوص تعداد سے زیادہ ہے تو اس کا مطلب ہے کہ پوزیشن انٹرفیس ڈیٹا میں تاخیر ہوئی ہے اور اس ٹرانزیکشن کی منطق ختم ہو گئی ہے۔
// 参数
/*
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);
}
// 检测directBreak 并且持仓未变的情况
if (preNeedOpen == needOpen && directBreak) {
Log("疑似仓位数据延迟,等待30秒", "#FF0000")
Sleep(30000)
nowPosition = GetPosition(e, contractType, direction);
if (nowPosition) {
needOpen = opAmount - (nowPosition.Amount - initAmount);
}
/*
timeoutCount++
if (timeoutCount > 10) {
Log("连续10次疑似仓位延迟,下单失败!", "#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, "开多仓", contractType, ticker);
} else {
orderId = e.Sell(ticker.Buy - SlidePrice, amount, "开空仓", 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, "平多仓", contractType, ticker);
} else if (position.Type == PD_SHORT) {
e.SetDirection("closesell");
e.Buy(ticker.Sell + SlidePrice, amount, "平空仓", 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。
ٹیمپلیٹ ایک بیٹا ورژن ہے تجاویز اور تبصرے کا خیرمقدم ہے ہم پوزیشن ڈیٹا میں تاخیر کے مسئلے کو حل کرنے کے لیے اسے بہتر بناتے رہیں گے۔