Für Anfänger, die Strategien entwerfen, ist eine Hedging-Strategie eine sehr gute Praktikerstrategie. Dieser Beitrag umfasst eine einfache, aber praktische digitale Währungs-Hardware-Hedging-Strategie, die es den Anfängern erlaubt, etwas Design-Erfahrung zu sammeln.
Zunächst einmal sollte klargestellt werden, dass die bevorstehende Strategie eine digitale Währung ist. Wir haben die einfachste Absicherung entworfen, bei der nur die Preiserhöhungen zwischen den beiden Börsen verkauft und die Preiserhöhungen bei den niedrigeren Börsen gekauft werden.
Bei der Abwicklung von Aufträgen gibt es Präzisionsbeschränkungen für den Preis, die Menge und die Börse. Es gibt auch Mindest-Einheitsbeschränkungen. Zusätzlich zu Mindest-Einheitsbeschränkungen berücksichtigt die Strategie bei der Abwicklung auch die maximale Aufträgsgröße einer Abwicklung, wenn die Abwicklung zu groß ist. Es muss auch berücksichtigt werden, wie der Wechselkurs umgewandelt wird, wenn die beiden Währungen unterschiedlich sind.
Aufgrund dieser Überlegungen muss die Strategie einige Parameter gestalten:
hedgeDiffPrice
, wenn die Differenz diesen Wert überschreitet, wird eine Hedging-Operation ausgelöst.minHedgeAmount
Das Mindestbetrag, das abgesichert werden kann, ist die Anzahl der Münzen.maxHedgeAmount
Die höchste Einheitsmenge für eine Hedging-Aktie (Koinzahl) ist:pricePrecisionA
Die Preispräzision der Börse A (kleine Ziffern)amountPrecisionA
, A ist die niedrigste Einheitspräzision (kleine Ziffern) der Börse.pricePrecisionB
,B-Börse, Preissteigerung (kleine Ziffern)amountPrecisionB
Die B-Börse hat eine niedrigere Einheitspräzision (kleine Ziffern) als die B-Börse.rateA
, der Wechselkurs des ersten hinzugefügten Austauschobjekts wird umgewandelt, 1 wird nicht umgewandelt.rateB
, die Währungskonversion des zweiten hinzugefügten Austauschobjekts, die standardmäßig 1 nicht konvertiert wird.Die Hedging-Strategie erfordert, dass die Anzahl der Münzen in den beiden Konten stets unverändert bleibt (d. h. keine Richtungsposition hält, neutral bleibt), so dass eine Balance-Logik in der Strategie erforderlich ist.
function updateAccs(arrEx) {
var ret = []
for (var i = 0 ; i < arrEx.length ; i++) {
var acc = arrEx[i].GetAccount()
if (!acc) {
return null
}
ret.push(acc)
}
return ret
}
Wenn nach dem Auftrag keine Transaktionen stattfinden, müssen wir die Bestellung rechtzeitig widerrufen und können die Bestellung nicht hängen lassen. Diese Operation muss sowohl im Ausgleichsmodul als auch in der Hedging-Logik bearbeitet werden, so dass eine vollständige Widerrufsfunktion für die Bestellung entworfen werden muss.
function cancelAll() {
_.each(exchanges, function(ex) {
while (true) {
var orders = _C(ex.GetOrders)
if (orders.length == 0) {
break
}
for (var i = 0 ; i < orders.length ; i++) {
ex.CancelOrder(orders[i].Id, orders[i])
Sleep(500)
}
}
})
}
Bei der Ausgleichszahl müssen wir in einer gewissen Tiefe der Daten die Preise finden, die bis zu einer bestimmten Anzahl von Münzen kumulieren, also benötigen wir eine Funktion wie diese, um sie zu bearbeiten.
function getDepthPrice(depth, side, amount) {
var arr = depth[side]
var sum = 0
var price = null
for (var i = 0 ; i < arr.length ; i++) {
var ele = arr[i]
sum += ele.Amount
if (sum >= amount) {
price = ele.Price
break
}
}
return price
}
Dann müssen wir die spezifischen Abwicklungsvorgänge für die Sicherung entwerfen und schreiben, und wir müssen sie als gleichzeitige Abwicklungen entwerfen:
function hedge(buyEx, sellEx, price, amount) {
var buyRoutine = buyEx.Go("Buy", price, amount)
var sellRoutine = sellEx.Go("Sell", price, amount)
Sleep(500)
buyRoutine.wait()
sellRoutine.wait()
}
Schließlich haben wir die Gestaltung der Balance-Funktion abgeschlossen, die ein wenig komplex ist.
function keepBalance(initAccs, nowAccs, depths) {
var initSumStocks = 0
var nowSumStocks = 0
_.each(initAccs, function(acc) {
initSumStocks += acc.Stocks + acc.FrozenStocks
})
_.each(nowAccs, function(acc) {
nowSumStocks += acc.Stocks + acc.FrozenStocks
})
var diff = nowSumStocks - initSumStocks
// 计算币差
if (Math.abs(diff) > minHedgeAmount && initAccs.length == nowAccs.length && nowAccs.length == depths.length) {
var index = -1
var available = []
var side = diff > 0 ? "Bids" : "Asks"
for (var i = 0 ; i < nowAccs.length ; i++) {
var price = getDepthPrice(depths[i], side, Math.abs(diff))
if (side == "Bids" && nowAccs[i].Stocks > Math.abs(diff)) {
available.push(i)
} else if (price && nowAccs[i].Balance / price > Math.abs(diff)) {
available.push(i)
}
}
for (var i = 0 ; i < available.length ; i++) {
if (index == -1) {
index = available[i]
} else {
var priceIndex = getDepthPrice(depths[index], side, Math.abs(diff))
var priceI = getDepthPrice(depths[available[i]], side, Math.abs(diff))
if (side == "Bids" && priceIndex && priceI && priceI > priceIndex) {
index = available[i]
} else if (priceIndex && priceI && priceI < priceIndex) {
index = available[i]
}
}
}
if (index == -1) {
Log("无法平衡")
} else {
// 平衡下单
var price = getDepthPrice(depths[index], side, Math.abs(diff))
if (price) {
var tradeFunc = side == "Bids" ? exchanges[index].Sell : exchanges[index].Buy
tradeFunc(price, Math.abs(diff))
} else {
Log("价格无效", price)
}
}
return false
} else if (!(initAccs.length == nowAccs.length && nowAccs.length == depths.length)) {
Log("错误:", "initAccs.length:", initAccs.length, "nowAccs.length:", nowAccs.length, "depths.length:", depths.length)
return true
} else {
return true
}
}
Diese Funktionen wurden nach den Bedürfnissen der Strategie gestaltet. Hier können Sie mit der Gestaltung der Hauptfunktionen beginnen.
Die Strategie auf FMZ ist:main
Die Funktion wird ausgeführt.main
Wir haben einige Strategien, die wir an den Anfang der Funktion anfangen müssen.
Name der Börse Da viele Aktionen in der Strategie auf Börsenobjekte ausgerichtet sind, wie zum Beispiel Akquisition, Bestellung usw. Kann es problematisch sein, jedes Mal einen langen Namen zu verwenden. Ein kleiner Trick ist es, einen einfachen Namen zu verwenden.
var exA = exchanges[0]
var exB = exchanges[1]
Das ist ein einfacher Weg, um später Code zu schreiben.
Wechselkurs, Präzisionsdesign
// 精度,汇率设置
if (rateA != 1) {
// 设置汇率A
exA.SetRate(rateA)
Log("交易所A设置汇率:", rateA, "#FF0000")
}
if (rateB != 1) {
// 设置汇率B
exB.SetRate(rateB)
Log("交易所B设置汇率:", rateB, "#FF0000")
}
exA.SetPrecision(pricePrecisionA, amountPrecisionA)
exB.SetPrecision(pricePrecisionB, amountPrecisionB)
Wenn die WechselkursparameterrateA
、rateB
Es gibt eine Einstellung von 1 (default ist 1), alsorateA != 1
oderrateB != 1
Der Wechselkurs wird nicht aktiviert, sodass keine Wechselkursumstellung eingerichtet wird.
Alle Daten zurücksetzen
Manchmal müssen alle Logs, Daten, die in den Registrierungsblättern liegen, gelöscht werden, wenn eine Politik gestartet wird.isReset
, und dann den initialierten Teil der Konstruktions-Rückstellungscode in der Strategie, z. B.:
if (isReset) { // 当isReset为真时重置数据
_G(null)
LogReset(1)
LogProfitReset()
LogVacuum()
Log("重置所有数据", "#FF0000")
}
Wiederherstellung der ursprünglichen Konto-Daten, Aktualisierung der aktuellen Konto-Daten
Die Strategie erfordert eine kontinuierliche Erfassung der ursprünglichen Kontovermögen gegenüber der gegenwärtigen Vermögenslage, um den Ausgleich zu bestimmen.nowAccs
Diese Variable wird verwendet, um die Daten des aktuellen Kontos zu speichern, mit der Funktion, die wir gerade entwickelt haben.updateAccs
Sie erhalten die Kontoinformationen der aktuellen Börse.initAccs
Für die Erfassung des ursprünglichen Kontozustands (Daten wie Anzahl der Münzen an Börsen A und B, Anzahl der Preise)initAccs
Erstmal benutzt_G()
Funktion Wiederherstellung ((_G Funktion wird dauerhaft aufgezeichnet und kann die aufgezeichneten Daten wiederherstellen, siehe API-Dokumentation:LinksWenn Sie keine Anfrage erhalten, verwenden Sie Ihre aktuellen Account-Informationen._G
Funktionsprotokolle.
Die folgenden Codes sind zum Beispiel:
var nowAccs = _C(updateAccs, exchanges)
var initAccs = _G("initAccs")
if (!initAccs) {
initAccs = nowAccs
_G("initAccs", initAccs)
}
Der Code in der Hauptschleife ist der Prozess, der von der Strategie-Logik pro Runde ausgeführt wird, und die ständige Wiederholung der Ausführung bildet den Hauptschleife.
Erhalten Sie Marktdaten, um zu beurteilen, wie effektiv sie sind
var ts = new Date().getTime()
var depthARoutine = exA.Go("GetDepth")
var depthBRoutine = exB.Go("GetDepth")
var depthA = depthARoutine.wait()
var depthB = depthBRoutine.wait()
if (!depthA || !depthB || depthA.Asks.length == 0 || depthA.Bids.length == 0 || depthB.Asks.length == 0 || depthB.Bids.length == 0) {
Sleep(500)
continue
}
Hier sehen Sie die Parallelfunktionen, die mit der FMZ-Plattform verwendet werden.exchange.Go
Sie haben einen Anruf erstellt.GetDepth()
Gleichzeitige Objekte der SchnittstelledepthARoutine
、depthBRoutine
│ Bei der Erstellung dieser beiden gleichzeitigen Objekte wird einGetDepth()
Die Schnittstelle wurde sofort eingerichtet, als beide Anfragen für die Vertiefungsdaten an die Börse weitergeleitet wurden.
Dann rufen Sie an.depthARoutine
、depthBRoutine
Gegenstandwait()
Die Methode zur Gewinnung von Daten in der Tiefe.
Nach dem Erhalt der Tiefendaten müssen die Tiefendaten überprüft werden, um ihre Wirksamkeit zu beurteilen.continue
Die Sätze führen den Hauptkreislauf wieder aus.
Nutzung价差值
Die Parameter?差价比例
Die Parameter?
var targetDiffPrice = hedgeDiffPrice
if (diffAsPercentage) {
targetDiffPrice = (depthA.Bids[0].Price + depthB.Asks[0].Price + depthB.Bids[0].Price + depthA.Asks[0].Price) / 4 * hedgeDiffPercentage
}
Wir haben die Parameter so gestaltet. FMZ-Parameter können auf Parametern basieren.angezeigtOderVerstecktAlso können wir eine Parameter machen, um zu entscheiden, ob wir sie verwenden.价格差
Oder差价比例
。
Ein Parameter wurde in die Strategie-Interface-Parameter hinzugefügtdiffAsPercentage
Die beiden anderen Optionen, die auf dieser Parameterbasis angezeigt oder versteckt werden, sind:hedgeDiffPrice@!diffAsPercentage
WenndiffAsPercentage
Für die falsche Anzeige dieses Parameters.hedgeDiffPercentage@diffAsPercentage
WenndiffAsPercentage
Die Parameter werden dann als wahr angezeigt.
Wir haben uns mit dem Design beschäftigt und haben uns für das Projekt entschieden.diffAsPercentage
Parameter, die als Auslöser für die Absicherung im Verhältnis zu den Differenzpreisen dienen.diffAsPercentage
Die Parameter werden von der Preisdifferenz als Auslöser für die Absicherung verwendet.
Begründung für die Auslösung von Hedges
if (depthA.Bids[0].Price - depthB.Asks[0].Price > targetDiffPrice && Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount) >= minHedgeAmount) { // A -> B 盘口条件满足
var price = (depthA.Bids[0].Price + depthB.Asks[0].Price) / 2
var amount = Math.min(depthA.Bids[0].Amount, depthB.Asks[0].Amount)
if (nowAccs[0].Stocks > minHedgeAmount && nowAccs[1].Balance / price > minHedgeAmount) {
amount = Math.min(amount, nowAccs[0].Stocks, nowAccs[1].Balance / price, maxHedgeAmount)
Log("触发A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, price, amount, nowAccs[1].Balance / price, nowAccs[0].Stocks) // 提示信息
hedge(exB, exA, price, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
} else if (depthB.Bids[0].Price - depthA.Asks[0].Price > targetDiffPrice && Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount) >= minHedgeAmount) { // B -> A 盘口条件满足
var price = (depthB.Bids[0].Price + depthA.Asks[0].Price) / 2
var amount = Math.min(depthB.Bids[0].Amount, depthA.Asks[0].Amount)
if (nowAccs[1].Stocks > minHedgeAmount && nowAccs[0].Balance / price > minHedgeAmount) {
amount = Math.min(amount, nowAccs[1].Stocks, nowAccs[0].Balance / price, maxHedgeAmount)
Log("触发B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, price, amount, nowAccs[0].Balance / price, nowAccs[1].Stocks) // 提示信息
hedge(exA, exB, price, amount)
cancelAll()
lastKeepBalanceTS = 0
isTrade = true
}
}
Es gibt verschiedene Auslöser für Hedging:
1. Das Hedging-Differenz-Parameter wird erst einmal erfüllt und nur dann abgesichert, wenn das Differenz-Differenz-Parameter des Aufschlags erfüllt wird.
2. Die in den Parametern festgelegte Mindest-Hedging-Menge muss von den unterschiedlichen Börsen mit unterschiedlichen Mindest-Hedging-Mengen abgedeckt werden.
3. Die Vermögenswerte an der Börse, an der die Operationen verkauft wurden, sind ausreichend, um sie zu verkaufen, und die Vermögenswerte an der Börse, an der die Operationen gekauft wurden, sind ausreichend, um sie zu kaufen.
Wenn diese Bedingungen erfüllt sind, wird die Hedge-Funktion ausgeführt. Vor der Hauptfunktion erklären wir eine Variable.isTrade
Hier wird die Variable als "Wenn ein Hedge ausgelöst wird" gesetzt.true
Und die globalen Variablen zurücksetzen.lastKeepBalanceTS
Als 0 (lastKeepBalanceTS wird verwendet, um den Timestamp der letzten Balance-Operation zu markieren, die auf 0 gesetzt wird, um die Balance-Operation sofort auszulösen) und dann alle Anhängsel zu löschen.
Ausgleichsoperationen
if (ts - lastKeepBalanceTS > keepBalanceCyc * 1000) {
nowAccs = _C(updateAccs, exchanges)
var isBalance = keepBalance(initAccs, nowAccs, [depthA, depthB])
cancelAll()
if (isBalance) {
lastKeepBalanceTS = ts
if (isTrade) {
var nowBalance = _.reduce(nowAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
var initBalance = _.reduce(initAccs, function(sumBalance, acc) {return sumBalance + acc.Balance}, 0)
LogProfit(nowBalance - initBalance, nowBalance, initBalance, nowAccs)
isTrade = false
}
}
}
Sie können sehen, dass die Balance-Funktion regelmäßig ausgeführt wird, aber wenn die Hedge-Operation nach dem Auslösen ausgelöst wird, dann wird die Balance-Funktion nach dem Auslösen ausgelöst.lastKeepBalanceTS
Die Balance-Operation wird sofort ausgelöst, wenn sie auf 0 gesetzt wird.
Status-Tablets
LogStatus(_D(), "A->B:", depthA.Bids[0].Price - depthB.Asks[0].Price, " B->A:", depthB.Bids[0].Price - depthA.Asks[0].Price, " targetDiffPrice:", targetDiffPrice, "\n",
"当前A,Stocks:", nowAccs[0].Stocks, "FrozenStocks:", nowAccs[0].FrozenStocks, "Balance:", nowAccs[0].Balance, "FrozenBalance", nowAccs[0].FrozenBalance, "\n",
"当前B,Stocks:", nowAccs[1].Stocks, "FrozenStocks:", nowAccs[1].FrozenStocks, "Balance:", nowAccs[1].Balance, "FrozenBalance", nowAccs[1].FrozenBalance, "\n",
"初始A,Stocks:", initAccs[0].Stocks, "FrozenStocks:", initAccs[0].FrozenStocks, "Balance:", initAccs[0].Balance, "FrozenBalance", initAccs[0].FrozenBalance, "\n",
"初始B,Stocks:", initAccs[1].Stocks, "FrozenStocks:", initAccs[1].FrozenStocks, "Balance:", initAccs[1].Balance, "FrozenBalance", initAccs[1].FrozenBalance)
Die Statusbar ist nicht besonders kompliziert gestaltet und zeigt die aktuelle Zeit an, zeigt die Differenz von A zu B und von B zu A. Sie zeigt die aktuelle Differenz des Hedging-Ziels. Sie zeigt die Anlagendaten von A, die Anlagendaten von B.
In den Parametern haben wir die Parameter für die Umwandlung von Wechselkurswerten entwickelt.main
Wir haben auch den Wechselkurs umgewandelt.SetRate
Die Wechselkurskonvertierungsfunktion muss zuerst ausgeführt werden.
Die Funktion wird auf zwei Ebenen eingesetzt:
BTC_USDT
Die Preise sind:USDT
Das ist eine sehr schwierige Aufgabe.USDT
Wenn ich einen Wert in CNY umwandeln möchte, dann kann ich das in meinem Code festlegen.exchange.SetRate(6.8)
Wir haben es.exchange
Alle Funktionsdaten, die unter diesem Austauschobjekt erfasst wurden, wurden in CNY umgerechnet.
Ich habe die Münze für den Preis bezahlt.SetRate
FunktionsübertragungWechselkurs der aktuellen Währung gegenüber der Zielwährung。Die volle Strategie:Die Strategie zur Hedging von verschiedenen Währungen
Die Squirrels sind großzügig.Sehr gut.