In dem vorherigen Artikel haben wir die Handelslogikanalyse einer einfachen Gitterstrategie erläutert.
Analyse der Handelslogik Wie wir in dem vorherigen Artikel erwähnt haben, können Sie eine Handelsaktion auslösen, indem Sie jede Rasterlinie durchqueren und den aktuellen Preis über oder unter den aktuellen Preis überschreiten.
Das erste Detail, das wir in Betracht ziehen müssen, ist das Design des unendlichen Rasters.createNet
Diese Funktion erzeugt eine Gitterdatenstruktur mit einer endlichen Anzahl von Gitterlinien. Was also, wenn der Preis über die Grenzen dieser Gitterdatenstruktur hinausgeht (über die obere Gitterlinie hinaus, wo der Preis am höchsten ist, und die untere Gitterlinie, wo der Preis am niedrigsten ist), wenn die Strategie ausgeführt wird?
Also müssen wir zunächst einen Erweiterungsmechanismus in die Netzwerkdatenstruktur hinzufügen.
Lasst uns mit dem Schreiben der Strategie-Hauptfunktion beginnen, die der Code ist, in dem die Strategie beginnt auszuführen.
var diff = 50 // Global variables and grid spacing can be designed as parameters for easy explanation. We write this parameter into the code.
function main() {
// After the real bot starts running, execute the strategy code from here
var ticker = _C(exchange.GetTicker) // To get the latest market data ticker, please refer to the FMZ API documentation for the structure of the ticker data: https://www.fmz.com/api#ticker
var net = createNet(ticker.Last, diff) // The function we designed in the previous article to construct the grid data structure initially, here we construct a grid data structure net
while (true) { // Then the program logic enters this while infinite loop, and the strategy execution will continue to execute the code within the {} symbol here.
ticker = _C(exchange.GetTicker) // The first line of the infinite loop code section, get the latest market data and update it to the ticker variable
// Check the grid range
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// There are other codes...
}
}
Die Netzdatenstruktur wird durch folgenden Code erweiterbar gemacht (auszug aus dem obigen Code):
// Check the grid range
while (ticker.Last >= net[net.length - 1].price) { // If the price exceeds the grid line of the highest price of the grid
net.push({ // Just add a new grid line after the grid line with the highest price of the grid
buy : false, // Initialize sell marker
sell : false, // Initialize buy marker
price : net[net.length - 1].price + diff, // dd a grid spacing to the previous highest price
})
}
while (ticker.Last <= net[0].price) { // If the price is lower than the grid line of the lowest price of the grid
var price = net[0].price - diff // Different from adding upwards, it should be noted that the price of adding new grid lines downwards cannot be less than or equal to 0, so it is necessary to judge here
if (price <= 0) { // Less than or equal to 0 will not be added, jump out of this loop
break
}
net.unshift({ // Add a new grid line just before the grid line with the lowest price of the grid
buy : false,
sell : false,
price : price,
})
}
Der nächste Schritt besteht darin, zu prüfen, wie der Handelsprozess konkret umgesetzt wird.
var diff = 50
var amount = 0.002 // Add a global variable, which can also be designed as a parameter. Of course, for the sake of simplicity, we also write it in the strategy code.
// This parameter controls the trade volume each time a trade is triggered on the grid line
function main() {
var ticker = _C(exchange.GetTicker)
var net = createNet(ticker.Last, diff)
var preTicker = ticker // Before the main loop (fixed loop) starts, set a variable to record the last market data
while (true) {
ticker = _C(exchange.GetTicker)
// Check the grid range
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// Retrieve grid
for (var i = 0 ; i < net.length ; i++) { // Iterate over all grid lines in the grid data structure
var p = net[i]
if (preTicker.Last < p.price && ticker.Last > p.price) { // Above the SMA, sell, the current node has already traded, regardless of SELL BUY, it will no longer be traded
if (i != 0) {
var downP = net[i - 1]
if (downP.buy) {
exchange.Sell(-1, amount, ticker)
downP.buy = false
p.sell = false
continue
}
}
if (!p.sell && !p.buy) {
exchange.Sell(-1, amount, ticker)
p.sell = true
}
} else if (preTicker.Last > p.price && ticker.Last < p.price) { // Below the SMA, buy
if (i != net.length - 1) {
var upP = net[i + 1]
if (upP.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
upP.sell = false
p.buy = false
continue
}
}
if (!p.buy && !p.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
p.buy = true
}
}
}
preTicker = ticker // Record the current market data in preTicker, and in the next cycle, use it as a comparison between the "previous" market data and the latest one to judge whether to be above the SMA or below the SMA.
Sleep(500)
}
}
Es kann festgestellt werden, dass:
preTicker.Last < p.price && ticker.Last > p.price
preTicker.Last > p.price && ticker.Last < p.price
Das haben wir im vorherigen Beitrag gesagt:
Die Beurteilung, ob der Bestellwert über oder unter dem SMA liegt, ist nur der erste Schritt, um zu beurteilen, ob ein Auftrag erteilt werden kann, und es ist auch notwendig, die Markierungen in den Netzlinie-Daten zu beurteilen.
Wenn es über der SMA liegt, wird beurteilt, dass der Preis niedriger ist als die aktuelle Gitterlinie und das Kaufzeichen auf der nächstgelegenen Gitterlinie. Wenn der Wert der Kaufzeichen wahr ist, bedeutet dies, dass die vorherige Gitterlinie gekauft wurde und die vorherige Kaufzeichen auf falsch zurückgesetzt, und die aktuelle Gitterlinie auf falsch zurückgesetzt.
Nach Beurteilung der Bedingungen, wenn es keinen Auslöser gibt, weiter zu beurteilen. Wenn die Kauf-/Verkaufsmarken auf der aktuellen Gitterlinie beide falsch sind, bedeutet dies, dass die aktuelle Gitterlinie gehandelt werden kann. Da sie über der SMA liegt, werden wir hier eine Verkaufsoperation durchführen. Nach der Ausführung markieren Sie die aktuelle Gitterlinie Verkaufsmarke wahr.
Die Verarbeitung Logik ist die gleiche für unterhalb der SMA (links für die Anfänger hier zu denken).
Um einige Daten während des Backtests zu sehen, muss eine FunktionshowTbl
wird geschrieben, um die Daten anzuzeigen.
function showTbl(arr) {
var tbl = {
type : "table",
title : "grid",
cols : ["grid information"],
rows : []
}
var arrReverse = arr.slice(0).reverse()
_.each(arrReverse, function(ele) {
var color = ""
if (ele.buy) {
color = "#FF0000"
} else if (ele.sell) {
color = "#00FF00"
}
tbl.rows.push([JSON.stringify(ele) + color])
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n account Information:", exchange.GetAccount())
}
Vollständiger Strategiecode:
/*backtest
start: 2021-04-01 22:00:00
end: 2021-05-22 00:00:00
period: 1d
basePeriod: 1m
exchanges: [{"eid":"OKEX","currency":"ETH_USDT","balance":100000}]
*/
var diff = 50
var amount = 0.002
function createNet(begin, diff) {
var oneSideNums = 10
var up = []
var down = []
for (var i = 0 ; i < oneSideNums ; i++) {
var upObj = {
buy : false,
sell : false,
price : begin + diff / 2 + i * diff,
}
up.push(upObj)
var j = (oneSideNums - 1) - i
var downObj = {
buy : false,
sell : false,
price : begin - diff / 2 - j * diff,
}
if (downObj.price <= 0) { // The price cannot be less than or equal to 0
continue
}
down.push(downObj)
}
return down.concat(up)
}
function showTbl(arr) {
var tbl = {
type : "table",
title : "grid",
cols : ["grid Information"],
rows : []
}
var arrReverse = arr.slice(0).reverse()
_.each(arrReverse, function(ele) {
var color = ""
if (ele.buy) {
color = "#FF0000"
} else if (ele.sell) {
color = "#00FF00"
}
tbl.rows.push([JSON.stringify(ele) + color])
})
LogStatus(_D(), "\n`" + JSON.stringify(tbl) + "`", "\n account Information:", exchange.GetAccount())
}
function main() {
var ticker = _C(exchange.GetTicker)
var net = createNet(ticker.Last, diff)
var preTicker = ticker
while (true) {
ticker = _C(exchange.GetTicker)
// Check the grid range
while (ticker.Last >= net[net.length - 1].price) {
net.push({
buy : false,
sell : false,
price : net[net.length - 1].price + diff,
})
}
while (ticker.Last <= net[0].price) {
var price = net[0].price - diff
if (price <= 0) {
break
}
net.unshift({
buy : false,
sell : false,
price : price,
})
}
// Retrieve grid
for (var i = 0 ; i < net.length ; i++) {
var p = net[i]
if (preTicker.Last < p.price && ticker.Last > p.price) { // Being above the SMA, sell, the current node has already traded, regardless of SELL BUY, it will no longer be traded
if (i != 0) {
var downP = net[i - 1]
if (downP.buy) {
exchange.Sell(-1, amount, ticker)
downP.buy = false
p.sell = false
continue
}
}
if (!p.sell && !p.buy) {
exchange.Sell(-1, amount, ticker)
p.sell = true
}
} else if (preTicker.Last > p.price && ticker.Last < p.price) { // Being below the SMA, buy
if (i != net.length - 1) {
var upP = net[i + 1]
if (upP.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
upP.sell = false
p.buy = false
continue
}
}
if (!p.buy && !p.sell) {
exchange.Buy(-1, amount * ticker.Last, ticker)
p.buy = true
}
}
}
showTbl(net)
preTicker = ticker
Sleep(500)
}
}
Strategie-Backtesting:
Wir können also die Eigenschaften der Netzstrategie sehen, wenn es einen Trendmarkt gibt, wird es einen großen schwimmenden Verlust geben, und der Gewinn wird in einem volatilen Markt zurückschlagen.
Daher ist die Netzstrategie nicht risikofrei. Die Spotstrategie kann immer noch um