Untuk masa yang lama, masalah kelewatan data antara muka API pertukaran mata wang kripto selalu mengganggu saya. Saya tidak menemui cara yang sesuai untuk mengatasinya. Saya akan menghasilkan semula adegan masalah ini.
Biasanya pesanan pasaran yang disediakan oleh bursa kontrak sebenarnya adalah harga pihak lawan, jadi kadang-kadang yang dipanggil
Masalah terletak pada maklumat kedudukan ini. jika pesanan ditutup, data yang dikembalikan oleh antara muka maklumat kedudukan pertukaran (iaitu antara muka pertukaran yang lapisan bawah sebenarnya mengakses apabila kita memanggilexchange.GetPosition
Jika data yang dikembalikan oleh bursa adalah data lama, iaitu maklumat kedudukan pesanan yang baru diletakkan sebelum transaksi selesai, ini akan menyebabkan masalah.
Logik perdagangan mungkin menganggap bahawa pesanan tidak telah dipenuhi dan terus meletakkan pesanan. Walau bagaimanapun, antara muka penempatan pesanan bursa tidak tertunda, tetapi urus niaga cepat, dan pesanan dilaksanakan. Ini akan menyebabkan akibat yang serius bahawa strategi akan berulang kali meletakkan pesanan ketika mencetuskan operasi membuka kedudukan.
Oleh kerana masalah ini, saya telah melihat strategi untuk mengisi kedudukan panjang gila, untungnya, pasaran telah meningkat pada masa itu, dan keuntungan terapung sekali melebihi 10BTC.
Ia adalah mungkin untuk merancang logik penempatan pesanan untuk strategi untuk meletakkan hanya satu pesanan. Harga penempatan pesanan adalah seluncur besar untuk jurang harga harga lawan pada masa itu, dan kedalaman tertentu pesanan lawan boleh dilaksanakan. Kelebihan ini adalah bahawa hanya satu pesanan diletakkan, dan ia tidak dinilai berdasarkan maklumat kedudukan. Ini dapat mengelakkan masalah penempatan pesanan berulang, tetapi kadang-kadang apabila harga berubah agak besar, pesanan akan mencetuskan mekanisme had harga bursa, dan ia boleh menyebabkan pesanan seluncur besar masih tidak selesai, dan terlepas peluang perdagangan.
Menggunakan
Kami masih menggunakan logik dagangan sebelumnya dan meletakkan pesanan had, tetapi kami menambah beberapa pengesanan ke dalam logik dagangan untuk cuba menyelesaikan masalah yang disebabkan oleh kelewatan data kedudukan. Selepas pesanan diletakkan, jika pesanan tidak dibatalkan, ia hilang secara langsung dalam senarai pesanan yang tertunda (daftar pesanan yang tertunda hilang dengan dua cara yang mungkin: 1 menarik balik pesanan, 2 dilaksanakan), mengesan keadaan tersebut dan meletakkan jumlah pesanan lagi. Jumlah pesanan terakhir adalah sama. Pada masa ini, perlu memberi perhatian kepada sama ada data kedudukan tertunda. Biarkan program memasukkan logik menunggu untuk mendapatkan semula maklumat kedudukan. Anda bahkan boleh terus mengoptimumkan dan meningkatkan jumlah menunggu pemicu. Jika melebihi beberapa kali, data antara muka kedudukan tertunda. Masalahnya serius, biarkan logik urus niaga dihentikan.
// 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")
}
Alamat templat:https://www.fmz.com/strategy/203258
Cara untuk memanggil antara muka templat adalah seperti$.OpenLong
dan$.CoverLong
dalammain
fungsi di atas.
Templat adalah versi beta, sebarang cadangan dialu-alukan, saya akan terus mengoptimumkan untuk menangani masalah kelewatan dalam data kedudukan.