前回の記事では、DATADATAプラットフォーム上の通貨を振幅と上昇と下降に基づいて予備スクリーニングしました。次に、グリッド取引における重要な要素であるグリッド数の設定について説明します。グリッドの数によって、取引の頻度と各取引の資金の量が決まり、グリッド取引の総収益とリスク レベルに影響します。したがって、最適なバランスポイントを達成するためにグリッドの数を合理的に設定する方法は、すべてのグリッドトレーダーが考慮する必要がある重要な問題です。
グリッドが少なすぎる: グリッドの数を小さく設定しすぎると、グリッド間の間隔が大きくなり、次のグリッドに到達するために価格がより大きく変動する必要が生じます。各グリッドの取引量は大きく、より大きな変動利益を獲得できるものの、取引機会が少ないため、より小さな変動によってもたらされる利益の一部を逃してしまう可能性があります。したがって、全体的な収益性は予想よりも低くなる可能性があります。
グリッドが多すぎる: グリッドの数を多く設定しすぎると、グリッドごとの価格帯が狭くなり、取引機会が増え、より頻繁に売買を行えるようになります。しかし、各取引に関わる資本の額が少ないため、このような戦略では利益を上げるために高頻度取引が必要になることがよくあります。これにより、取引手数料が簡単に高くなる可能性があり、取引頻度が高すぎると、小さな市場変動が主な利益源となり、利益の上限が制限される可能性があります。
適切なグリッド数適切なグリッド数を決定するには、市場のボラティリティ、口座サイズ、予想される取引頻度を考慮する必要があります。市場のボラティリティが高い場合、グリッドの数を適切に増やすことで変動をより適切に捉えることができますが、資金が大きい場合は、グリッドの数を少なく設定すると、1回の取引金額が高くなり、取引手数料の圧力が軽減される可能性があります。グリッド間隔と頻繁な取引のコストのバランスをとることで、戦略の収益とリスク管理を最大化できます。
グリッド取引の中心的な機能は、複数のグリッド間隔を設定して各間隔に資金を割り当てることです。グリッドの数を決定するときは、まず各グリッド間の間隔と各グリッド内の資金の量を計算する必要があります。グリッド数の設定は、各グリッド内の資金の量に影響するだけでなく、各グリッドの売買価格の範囲も決定します。
アカウント資金はグリッドの数を決定する重要な要素です。アカウント資金が大きいほど、より多くのグリッドを設定できますが、アカウント資金が小さい場合は、資金の割り当てが分散しすぎて各グリッドの資金が少なくなり、効果的に利益を上げることができなくなるのを避けるために、グリッドの数に制限が必要です。
さらに、グリッド取引のリスク管理戦略では、グリッド数の設定も考慮する必要があります。特に市場が激しく変動している場合には、グリッドが多すぎると損失が大きくなる可能性があるため、過剰な取引を避けるためにグリッドの数を合理的に制御する必要があります。
グリッド取引戦略の実際の適用において、特にグリッド数と収益率のバランスを最適化する場合、Datadata プラットフォームの DQL (Datadata Query Language) は大きな柔軟性を提供します。 DQL は、効率的なデータ クエリ、処理、分析をサポートするだけでなく、トレーダーがグリッド取引戦略のパフォーマンスをシミュレートおよびバックテストして、最も適切なグリッド番号やその他のパラメーター構成を見つけるのにも役立ちます。
DQL を使用すると、複数の取引所 (Binance など) から過去の K ライン データを簡単に取得し、このデータに基づいてグリッド取引戦略を調整できます。このようにして、さまざまな市場環境や特定の通貨のボラティリティに応じて、最適なグリッド取引戦略を正確にスクリーニングすることができます。
グリッド取引戦略のバックテストを開始する前に、まず対象通貨の市場データを取得する必要があります。以下は、データベースから指定された通貨の K ライン データを照会するためのコードです。
# 获取目标币种的K线数据
data = query("select * from klines.spot_1d where Exchange = 'Binance' and Symbol = '???_usdt' order by Time")
解説:
???_usdt
)をBinance取引プラットフォームで確認できます(時間、始値、最高値、最低値、終値など)。これにより、戦略実行のための基本データが提供されます。グリッド取引戦略の中核は、事前に設定されたグリッド数量と価格範囲を使用して取引することです。具体的な手順は次のとおりです。
グリッド間隔(ギャップ)とグリッドあたりの取引額(想定額)を計算する:
グリッド間隔(ギャップ): 市場における最高価格と最低価格の比率に基づいて計算されます。式は次のとおりです。
[
\text{gap} = \frac{\log(\text{max_p} / \text{min_p})}{\text{grid_num}}
]
で、max_p
最高価格で、min_p
最低価格で、grid_num
グリッドの数です。
グリッドあたりの取引金額(名目):各グリッドの取引量は、総資金とグリッド数によって計算されます。式は次のとおりです。 [ \text{notional} = \frac{\text{balance}}{\text{grid_num}} ]
グリッドの開始価格と終了価格:
exp(gap)
、 等々。トレーディング業務:
取引手数料: 各取引の手数料が 0.0001 であると仮定すると、各取引の手数料を計算して累積する必要があります。
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
対象通貨には、「oax_usdt」通貨を選択します。前回の記事のコードを確認したところ、この通貨は大きな一方的なトレンドを示さずに長期間にわたって高い振幅を維持しています。シミュレートされたバックテストに異なるグリッド番号(たとえば、5、10、15など)を使用して、異なるグリッド番号の効果を確認し、適切なグリッド番号を見つけることができます。たとえば、グリッド番号ごとに純利益(pl-net)を計算することで、現在の市場環境においてどのグリッド番号が最高の収益をもたらすかを評価できます。バックテストを実行するコードは次のとおりです。
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
さまざまなグリッド番号構成でバックテストを行った結果、次の結果が得られました。
分析:
グリッドの数を適切に設定することは、グリッド取引戦略において重要なタスクです。グリッドの数を最適化することで、グリッド取引戦略の利益パフォーマンスを効果的に向上させ、リスクをより適切に管理することができます。この記事では、グリッド番号の設定を分析し、具体的な計算方法とサンプルコードを提供し、グリッド取引戦略を最適化し、戦略の安定性と収益性を向上させることに貢献したいと考えています。
注記: この記事のグリッドバックテストコードはZhihu Da Shenから引用したものです。 Halcyon、ソースコードの説明については記事を参照してくださいアルゴリズムトレード実践日記(XVIII) - グリッドトレードの詳細:グリッド番号と長期リターンの関係。