Im vorherigen Artikel haben wir auf der DATADATA-Plattform ein vorläufiges Screening der Währungen basierend auf Amplitude sowie Anstieg und Fall durchgeführt. Als Nächstes werden wir einen Schlüsselfaktor im Grid-Trading untersuchen – die Festlegung der Grid-Anzahl. Die Anzahl der Grids bestimmt die Häufigkeit der Transaktionen und die Höhe der Mittel für jede Transaktion, was wiederum die Gesamtrendite und das Risikoniveau des Grid-Handels beeinflusst. Daher ist die Frage, wie die Anzahl der Gitter sinnvoll festgelegt werden kann, um den besten Gleichgewichtspunkt zu erreichen, eine wichtige Frage, die jeder Gitterhändler berücksichtigen muss.
Zu wenige Raster: Wenn die Anzahl der Raster zu klein eingestellt ist, sind die Abstände zwischen den Rastern größer, was bedeutet, dass der Preis stärker schwanken muss, um das nächste Raster zu erreichen. Obwohl der Transaktionsbetrag jedes Rasters größer ist und größere Schwankungsgewinne erzielen kann, können aufgrund geringerer Handelsmöglichkeiten einige durch kleinere Schwankungen erzielte Gewinne verloren gehen. Daher kann die Gesamtrentabilität geringer ausfallen als erwartet.
Zu viele Gitter: Wenn die Anzahl der Raster zu hoch eingestellt ist, ist die Preisspanne jedes Rasters kleiner, die Handelsmöglichkeiten steigen und Käufe und Verkäufe können häufiger durchgeführt werden. Da bei jeder Transaktion nur geringe Kapitalbeträge im Spiel sind, ist bei solchen Strategien zur Erzielung von Gewinnen jedoch häufig Hochfrequenzhandel erforderlich. Dies kann leicht zu höheren Transaktionsgebühren führen und zu häufiges Handeln kann dazu führen, dass kleine Marktschwankungen zur Hauptgewinnquelle werden, wobei den Gewinnen nach oben keine Grenzen gesetzt sind.
Angemessene Anzahl an Gittern: Bei der Auswahl der geeigneten Anzahl von Rastern müssen die Marktvolatilität, die Kontogröße und die erwartete Handelshäufigkeit berücksichtigt werden. Bei hoher Marktvolatilität können Schwankungen durch eine entsprechende Erhöhung der Rasteranzahl besser aufgefangen werden, während bei großen Fonds die Festlegung einer geringeren Rasteranzahl zu höheren Einzeltransaktionsbeträgen führen und den Druck auf die Transaktionsgebühren verringern kann. Durch einen Ausgleich des Rasterabstands und der Kosten häufigen Handels können die Erträge und die Risikokontrolle der Strategie maximiert werden.
Ein Kernmerkmal des Grid-Tradings besteht darin, den einzelnen Intervallen durch die Festlegung mehrerer Grid-Intervalle Mittel zuzuweisen. Um die Anzahl der Raster zu bestimmen, müssen Sie zunächst den Abstand zwischen den einzelnen Rastern und die Höhe der Mittel in jedem Raster berechnen. Die Festlegung der Anzahl der Raster wirkt sich nicht nur auf die Höhe der Mittel in jedem Raster aus, sondern bestimmt auch die Kauf- und Verkaufspreisspanne jedes Rasters.
Bei der Bestimmung der Rasteranzahl ist die Kontodeckung ein wichtiger Faktor. Bei größeren Kontofonds können mehr Raster erstellt werden, während bei kleineren Kontofonds die Anzahl der Raster begrenzt sein muss, um eine zu gestreute Mittelzuweisung zu vermeiden, die zu einer zu geringen Mittelmenge in jedem Raster und damit zur Folge hätte, dass kein effektiver Gewinn erzielt werden kann.
Darüber hinaus muss die Risikomanagementstrategie des Netzhandels auch die Festlegung der Netzanzahl berücksichtigen. Insbesondere bei starken Marktschwankungen können zu viele Netze zu größeren Verlusten führen. Daher sollte die Anzahl der Netze angemessen kontrolliert werden, um übermäßigen Handel zu vermeiden.
Bei der tatsächlichen Anwendung von Grid-Trading-Strategien, insbesondere bei der Optimierung des Gleichgewichts zwischen der Anzahl der Grids und der Rendite, bietet die DQL (Datadata Query Language) der Datadata-Plattform große Flexibilität. DQL unterstützt nicht nur eine effiziente Datenabfrage, -verarbeitung und -analyse, sondern hilft Händlern auch dabei, die Leistung von Grid-Trading-Strategien zu simulieren und Backtests durchzuführen, um die am besten geeignete Grid-Nummer und andere Parameterkonfigurationen zu finden.
Über DQL können wir problemlos historische K-Line-Daten von mehreren Börsen (wie Binance) abrufen und Grid-Trading-Strategien auf der Grundlage dieser Daten anpassen. Auf diese Weise kann die optimale Grid-Trading-Strategie entsprechend unterschiedlicher Marktumgebungen und der Volatilität bestimmter Währungen genau geprüft werden.
Bevor wir mit dem Backtesting unserer Grid-Trading-Strategie beginnen, müssen wir zunächst Marktdaten für die Zielwährung beschaffen. Nachfolgend sehen Sie den Code zum Abfragen der K-Line-Daten einer bestimmten Währung aus der Datenbank:
# 获取目标币种的K线数据
data = query("select * from klines.spot_1d where Exchange = 'Binance' and Symbol = '???_usdt' order by Time")
Erklärungen:
???_usdt
) auf der Binance-Handelsplattform (einschließlich Uhrzeit, Eröffnungskurs, Höchstkurs, Tiefstkurs und Schlusskurs usw.). Dies liefert grundlegende Daten für die Strategieumsetzung.Der Kern der Grid-Trading-Strategie besteht darin, mit einer voreingestellten Grid-Menge und Preisspanne zu handeln. Die einzelnen Schritte sind wie folgt:
Berechnen Sie das Rasterintervall (Gap) und den Transaktionsbetrag pro Raster (Nominalwert).:
Rasterabstand (Lücke): Berechnet basierend auf dem Verhältnis zwischen den höchsten und niedrigsten Preisen auf dem Markt. Die Formel lautet wie folgt:
[
\text{gap} = \frac{\log(\text{max_p} / \text{min_p})}{\text{grid_num}}
]
In,max_p
Für den höchsten Preis,min_p
Zum niedrigsten Preis,grid_num
ist die Anzahl der Gitter.
Transaktionsbetrag pro Raster (nominal): Der Transaktionsbetrag jedes Rasters wird anhand der Gesamtmittel und der Anzahl der Raster berechnet. Die Formel lautet: [ \text{notional} = \frac{\text{balance}}{\text{grid_num}} ]
Netzanfangs- und Netzendepreise:
exp(gap)
, und so weiter.Handelsgeschäfte:
Transaktionsgebühren: Angenommen, die Bearbeitungsgebühr für jede Transaktion beträgt 0,0001, dann müssen wir die Bearbeitungsgebühr für jede Transaktion berechnen und kumulieren.
def grid_trading_strategy(
raw,
grid_num, # 网格数量
min_p, # 最低价格
max_p, # 最高价格
):
"""
执行网格交易策略的函数
"""
# 初始化变量
balance = 1000 # 初始资金
raw = raw[['Time', 'Open', 'High', 'Low', 'Close']] # 只选择相关列
# 网格交易策略的设置
gap = math.log(max_p / min_p) / grid_num # 计算网格间隔
notional = balance / grid_num # 每个网格的交易额
# 初始化网格
net = []
for i in range(grid_num):
net.append({
'start_p': min_p * math.exp(i * gap), # 每个网格的起始价格
'end_p': min_p * math.exp((i + 1) * gap), # 每个网格的结束价格
'amt': notional / (min_p * math.exp(i * gap)), # 每个网格的购买量
'status': 'idle' # 初始状态为闲置
})
# 记录状态
state = {
'stock': 0, # 当前持仓
'fee': 0, # 交易费用
'longTradeVol': 0, # 长期交易量
'shortTradeVol': 0, # 短期交易量
'profitTbl': [], # 存储每个时刻的利润
'feeTbl': [], # 存储每个时刻的费用
'netCnt': 0, # 记录净交易次数
'idx': 0 # 当前数据的索引
}
# 检查开盘交易
def check_open_orders(state, net):
for i in range(len(net)):
if net[i]['status'] == 'idle' and raw['Low'][state['idx']] <= net[i]['start_p'] and raw['Open'][state['idx']] > net[i]['start_p']:
net[i]['status'] = 'taken' # 网格被占用
tradeVol = net[i]['amt'] * net[i]['start_p']
state['stock'] += net[i]['amt']
state['longTradeVol'] += tradeVol
state['fee'] += tradeVol * 0.0001 # 假设手续费为0.0001
# 检查平仓交易
def check_close_orders(state, net):
for i in range(len(net)):
if net[i]['status'] == 'taken' and raw['High'][state['idx']] >= net[i]['end_p'] and raw['Open'][state['idx']] < net[i]['end_p']:
net[i]['status'] = 'idle' # 网格状态恢复为空闲
tradeVol = net[i]['amt'] * net[i]['end_p']
state['stock'] -= net[i]['amt']
state['shortTradeVol'] += tradeVol
state['fee'] += tradeVol * 0.0001 # 假设手续费为0.0001
state['netCnt'] += 1
# 日志记录利润和费用
def log(state):
addVol = state['stock'] * raw['Close'][state['idx']] # 当前仓位的总价值
pl = state['shortTradeVol'] - state['longTradeVol'] + addVol # 计算利润
state['profitTbl'].append(pl)
state['feeTbl'].append(state['fee'])
# 主交易循环
for i in range(len(raw)):
state['idx'] = i
if raw['Close'][state['idx']] >= raw['Open'][state['idx']]:
check_open_orders(state, net)
check_close_orders(state, net)
else:
check_close_orders(state, net)
check_open_orders(state, net)
log(state)
# 将利润和费用数据整理为DataFrame
pl = DataFrame({'pl' : state['profitTbl'], 'fee' : state['feeTbl']})
pl['time'] = raw['Time']
pl['pl-net'] = pl['pl'] - pl['fee']
return pl
Als Zielwährung wählen wir die Währung „oax_usdt“. Nach Überprüfung des Codes im vorherigen Artikel behält diese Währung über einen langen Zeitraum eine hohe Amplitude bei, ohne einen signifikanten einseitigen Trend zu zeigen. Wir können versuchen, verschiedene Rasternummern (z. B. 5, 10, 15 usw.) für simuliertes Backtesting zu verwenden, um die Auswirkungen verschiedener Rasternummern zu sehen und dann eine geeignete Rasternummer zu finden. Indem wir beispielsweise den Nettogewinn (pl-net) für jede Gitternummer berechnen, können wir beurteilen, welche Gitternummern im aktuellen Marktumfeld die besten Renditen bringen können. Hier ist der Code zum Ausführen des Backtests:
grid_nums = [5*i+5 for i in range(5)]
out = []
for g in grid_nums:
pl = grid_trading_strategy(
data,
grid_num=g,
min_p=min(data['Close']),
max_p=max(data['Close'])
)
out.append({
'num': g,
'pl-net': pl['pl-net'][-1],
'min_pl': min(pl['pl-net']),
'max_pl': max(pl['pl-net'])
})
return out
Nach dem Backtesting mit verschiedenen Rasternummernkonfigurationen haben wir folgende Ergebnisse erhalten:
Analyse:
Die richtige Festlegung der Anzahl der Gitter ist eine wichtige Aufgabe in der Gitterhandelsstrategie. Durch die Optimierung der Grid-Anzahl können die Gewinnentwicklung von Grid-Trading-Strategien effektiv verbessert und Risiken besser kontrolliert werden. Dieser Artikel analysiert die Rasternummerneinstellungen und bietet spezifische Berechnungsmethoden und Beispielcodes. Er soll jedem dabei helfen, Rasterhandelsstrategien zu optimieren und die Stabilität und Rentabilität von Strategien zu verbessern.
Hinweis: Der Grid-Backtesting-Code in diesem Artikel wurde von Zhihu Da Shen übernommen. Halcyon, bitte lesen Sie den Artikel für eine Erklärung des QuellcodesPraxistagebuch zum Algorithmischen Handel (XVIII) - Details zum Grid-Trading: Die Beziehung zwischen Grid-Nummer und langfristiger Rendite。