Seit langem stört mich das Datenverzögerungsproblem der Position API-Schnittstelle des digitalen Währungsaustauschs immer. Ich habe keinen ordnungsgemäßen Weg gefunden, um mit diesem Problem umzugehen. Lassen Sie mich die Szene des Problems reproduzieren. Normalerweise ist der vom Vertragsaustausch bereitgestellte Marktpreisbefehl tatsächlich der Gegenparteipreis, so dass es manchmal nicht zuverlässig ist, diesen sogenannten
Aufgrund dieses Problems habe ich gesehen, wie eine Strategie voller Long-Positionen verrückt geöffnet wurde. Glücklicherweise stieg der Markt zu dieser Zeit an und der schwimmende Gewinn überstieg 10 BTC. Glücklicherweise stieg der Markt stark an. Wenn er stark sank, können wir uns das Ergebnis vorstellen.
Lösung 1 Die Strategie kann so konzipiert werden, dass nur ein Auftrag erteilt wird, und der Auftragspreis ist der Preis des aktuellen Handelsgegners plus ein großer gleitender Preis, um eine gewisse Tiefe der Auftragsgegnung des Gegners zu erreichen. Der Vorteil ist, dass nur ein Auftrag erteilt wird und nicht anhand der Positionsinformationen beurteilt wird. Dies kann das Problem der wiederholten Aufträge vermeiden, aber manchmal kann die Platzierung eines Auftrags den Preislimitmechanismus der Börse auslösen, wenn die Preisänderung relativ groß ist, und es ist möglich, den gleitenden Preis zu erhöhen und trotzdem keinen Deal zu machen, wodurch die Gelegenheit verpasst wird.
Lösung 2 Mit der Marktpreis-Orderfunktion der Börse wird der Preis auf - 1 auf dem FMZ als Marktpreis-Order übertragen.
Lösung 3 Wir verwenden immer noch die vorherige Handelslogik und platzieren Aufträge mit Preislimit-Orders, aber wir fügen etwas Erkennung in die Handelslogik hinzu, um zu versuchen, das Problem zu lösen, das durch die Verzögerung der Positionsdaten verursacht wird. Überprüfen Sie, ob die Bestellung direkt aus der Liste der ausstehenden Aufträge ohne Stornierung verschwunden ist (es gibt zwei Möglichkeiten zum Verschwinden aus der Liste der ausstehenden Aufträge: 1. Stornierung und 2. Ausgefüllt). Wenn eine solche Situation erkannt wird und die Menge der erneut platzierten Bestellung die gleiche ist wie die der letzten Bestellung, ist es wichtig zu beachten, ob die Positionsdaten verzögert sind. Lassen Sie das Programm die Wartelogik eingeben, um die Positionsinformationen wiederzuerlangen, oder sogar die Anzahl der Wartezeiten auszulösen, wenn sie eine bestimmte Anzahl von Positionsdaten überschreitet, zeigt dies an, dass die Interfaceverzögerung ernst ist, was dazu führt, dass die Handelslogik beendet wird.
// 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")
}
Adresse der Vorlage:https://www.fmz.com/strategy/203258
Die Schablonenoberfläche wird auf die gleiche Weise aufgerufen wie$.OpenLong
, $.CoverLong
in der oberen Hauptfunktion.
Die Vorlage ist eine Beta-Version, und Sie sind herzlich eingeladen, Vorschläge zu machen. Wir werden sie weiterhin optimieren, damit wir mit dem Problem der Verzögerung der Positionsdaten umgehen können.