Untuk masa yang lama, masalah kelewatan data antara muka API kedudukan bursa mata wang digital selalu mengganggu saya. Saya belum menemui cara yang betul untuk menangani masalah ini. Izinkan saya menghasilkan semula adegan masalah. Biasanya, pesanan harga pasaran yang disediakan oleh pertukaran kontrak sebenarnya adalah harga lawan, jadi kadang-kadang tidak boleh dipercayai untuk menggunakan apa yang disebut
Oleh kerana masalah ini, saya telah melihat strategi terbuka penuh dengan kedudukan panjang dengan gila. Mujurlah, pasaran melonjak pada masa itu, dan keuntungan terapung melebihi 10BTC. Mujurlah, pasaran meningkat dengan mendadak. Jika menurun dengan mendadak, kita boleh bayangkan hasilnya.
Penyelesaian 1 Strategi ini boleh direka untuk meletakkan hanya satu pesanan, dan harga pesanan adalah harga lawan dagangan semasa ditambah dengan harga bergerak yang besar, untuk mengambil kedalaman tertentu dari pesanan lawan. Kelebihan ini adalah bahawa hanya satu pesanan akan diletakkan, dan ia tidak akan dinilai berdasarkan maklumat kedudukan. Ini dapat mengelakkan masalah pesanan berulang, tetapi kadang-kadang meletakkan pesanan boleh mencetuskan mekanisme had harga bursa apabila perubahan harga agak besar, dan mungkin untuk meningkatkan harga bergerak dan masih gagal membuat perjanjian, dengan itu kehilangan peluang.
Penyelesaian 2 Dengan fungsi pesanan harga pasaran bursa, harga dipindahkan ke - 1 di FMZ sebagai pesanan harga pasaran.
Penyelesaian 3 Kami masih menggunakan logik dagangan sebelumnya dan meletakkan pesanan dengan pesanan had harga, tetapi kami menambah beberapa pengesanan dalam logik dagangan untuk cuba menyelesaikan masalah yang disebabkan oleh kelewatan data kedudukan. Semak sama ada pesanan telah hilang secara langsung dari senarai pesanan yang menunggu tanpa pembatalan (ada dua kemungkinan untuk hilang dari senarai pesanan yang menunggu: 1. Pembatalan dan 2. Diisi). Jika situasi seperti itu dikesan, dan kuantiti pesanan yang diletakkan lagi adalah sama dengan pesanan terakhir, penting untuk diperhatikan sama ada data kedudukan tertunda. Biarkan program memasukkan logik menunggu untuk mendapatkan semula maklumat kedudukan, atau bahkan terus mengoptimumkan dan meningkatkan jumlah masa menunggu untuk mencetuskan masa menunggu, jika melebihi bilangan masa kedudukan tertentu, ia menunjukkan bahawa kelewatan data antara muka adalah serius, yang menyebabkan logik perdagangan dihentikan.
// Parameters
/*
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);
}
// Check directBreak and the position remains unchanged
if (preNeedOpen == needOpen && directBreak) {
Log("Suspected position data is delayed, wait for 30 seconds", "#FF0000")
Sleep(30000)
nowPosition = GetPosition(e, contractType, direction);
if (nowPosition) {
needOpen = opAmount - (nowPosition.Amount - initAmount);
}
/*
timeoutCount++
if (timeoutCount > 10) {
Log("Suspected position is delayed for 10 consecutive times, and the order is failed!", "#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 positions", contractType, ticker);
} else {
orderId = e.Sell(ticker.Buy - SlidePrice, amount, "open short positions", 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 positions", contractType, ticker);
} else if (position.Type == PD_SHORT) {
e.SetDirection("closesell");
e.Buy(ticker.Sell + SlidePrice, amount, "close short positions", 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
Antara muka templat dipanggil dengan cara yang sama seperti$.OpenLong
, $.CoverLong
dalam fungsi utama di atas.
Templat ini adalah versi beta, dan anda dialu-alukan untuk membuat cadangan. Kami akan terus mengoptimumkannya supaya kita boleh menangani masalah kelewatan data kedudukan.