Seit langer Zeit beunruhigt mich das Datenverzögerungsproblem der API-Schnittstelle der Kryptowährungsbörse. Ich habe keinen geeigneten Weg gefunden, damit umzugehen. Ich werde die Szene dieses Problems reproduzieren.
Normalerweise ist der Marktbefehl, der von der Kontraktbörse bereitgestellt wird, tatsächlich der Gegenparteipreis, so dass manchmal die sogenannte
Das Problem liegt in dieser Position Informationen. Wenn die Bestellung geschlossen wird, die Daten zurückgegeben von der Exchange Position Information Interface (dh die Exchange-Schnittstelle, die die untere Schicht tatsächlich zugreift, wenn wir anrufenexchange.GetPosition
) sollte die Informationen der neu eröffneten Position enthalten, aber wenn die von der Börse zurückgegebenen Daten alte Daten sind, d. h. die Positionsinformationen der Order, die gerade vor Abschluss der Transaktion platziert wurde, wird dies zu einem Problem führen.
Die Handelslogik kann davon ausgehen, dass die Bestellung nicht ausgeführt wurde und die Bestellung weiterhin platziert wird. Allerdings wird die Bestellplatzierungsoberfläche der Börse nicht verzögert, sondern die Transaktion ist schnell und die Bestellung wird ausgeführt. Dies führt zu einer schweren Konsequenz, dass die Strategie beim Auslösen der Operation der Eröffnung einer Position wiederholt Aufträge platziert.
Aufgrund dieses Problems habe ich eine Strategie gesehen, um eine lange Position verrückt zu füllen, glücklicherweise war der Markt zu dieser Zeit gestiegen, und der schwimmende Gewinn überschritt einmal 10BTC. Glücklicherweise ist der Markt explodiert. Wenn es ein Sturz ist, kann sich das Ende vorstellen.
Es ist möglich, die Logik der Auftragserteilung für die Strategie zu entwerfen, nur einen Auftrag zu erteilen. Der Auftragserteilungspreis ist eine große Verschiebung für die Preislücke des gegnerischen Preises zu diesem Zeitpunkt, und eine gewisse Tiefe der gegnerischen Aufträge kann ausgeführt werden. Der Vorteil ist, dass nur ein Auftrag erteilt wird, und es wird nicht auf der Grundlage von Positionsinformationen beurteilt. Dies kann das Problem der wiederholten Auftragserteilung vermeiden, aber manchmal, wenn der Preis relativ stark ändert, wird der Auftrag den Preislimitmechanismus der Börse auslösen, und es kann dazu führen, dass der große Schiebungsauftrag immer noch nicht abgeschlossen ist und die Handelsmöglichkeit verpasst wird.
Mit Hilfe der
Wir verwenden immer noch die vorherige Handelslogik und platzieren eine Limitorder, aber wir fügen der Handelslogik etwas Erkennung hinzu, um zu versuchen, das Problem zu lösen, das durch die Verzögerung der Positionsdaten verursacht wird. Nachdem der Auftrag platziert wurde, verschwindet er, wenn der Auftrag nicht storniert wird, direkt in der Liste der ausstehenden Aufträge (die Liste der ausstehenden Aufträge verschwindet auf zwei mögliche Arten: 1 Abholung der Bestellung, 2 ausgeführt), erkennt eine solche Situation und platziert den Auftragsbetrag erneut. Der Betrag der letzten Bestellung ist der gleiche. Zu diesem Zeitpunkt ist es notwendig, darauf zu achten, ob die Positionsdaten verzögert sind. Lassen Sie das Programm die Wartenlogik eingeben, um die Positionsinformationen wiederzuerlangen. Sie können sogar die Anzahl der Auslöschwartungen weiter optimieren und erhöhen. Wenn sie eine bestimmte Anzahl von Mal überschreitet, verzögert sich die Positionsinterface. Das Problem ist ernst, lassen Sie die
// 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")
}
Adresse der Vorlage:https://www.fmz.com/strategy/203258
Die Art und Weise, die Schablonenoberfläche aufzurufen, ist genau wie$.OpenLong
und$.CoverLong
in dermain
Funktion oben.
Die Vorlage ist eine Beta-Version, jegliche Vorschläge sind willkommen, ich werde weiterhin optimieren, um mit dem Problem der Verzögerungen in Positionsdaten umzugehen.