2
フォロー
20
フォロワー

DATADATAはグリッド戦略(II)をサポートします:グリッド数と収益率の関係

作成日:: 2025-02-13 16:22:36, 更新日:: 2025-02-17 17:38:52
comments   0
hits   352

前回の記事では、DATADATAプラットフォーム上の通貨を振幅と上昇と下降に基づいて予備スクリーニングしました。次に、グリッド取引における重要な要素であるグリッド数の設定について説明します。グリッドの数によって、取引の頻度と各取引の資金の量が決まり、グリッド取引の総収益とリスク レベルに影響します。したがって、最適なバランスポイントを達成するためにグリッドの数を合理的に設定する方法は、すべてのグリッドトレーダーが考慮する必要がある重要な問題です。

グリッド数の設定の課題

  • グリッドが少なすぎる: グリッドの数を小さく設定しすぎると、グリッド間の間隔が大きくなり、次のグリッドに到達するために価格がより大きく変動する必要が生じます。各グリッドの取引量は大きく、より大きな変動利益を獲得できるものの、取引機会が少ないため、より小さな変動によってもたらされる利益の一部を逃してしまう可能性があります。したがって、全体的な収益性は予想よりも低くなる可能性があります。

  • グリッドが多すぎる: グリッドの数を多く設定しすぎると、グリッドごとの価格帯が狭くなり、取引機会が増え、より頻繁に売買を行えるようになります。しかし、各取引に関わる資本の額が少ないため、このような戦略では利益を上げるために高頻度取引が必要になることがよくあります。これにより、取引手数料が簡単に高くなる可能性があり、取引頻度が高すぎると、小さな市場変動が主な利益源となり、利益の上限が制限される可能性があります。

  • 適切なグリッド数適切なグリッド数を決定するには、市場のボラティリティ、口座サイズ、予想される取引頻度を考慮する必要があります。市場のボラティリティが高い場合、グリッドの数を適切に増やすことで変動をより適切に捉えることができますが、資金が大きい場合は、グリッドの数を少なく設定すると、1回の取引金額が高くなり、取引手数料の圧力が軽減される可能性があります。グリッド間隔と頻繁な取引のコストのバランスをとることで、戦略の収益とリスク管理を最大化できます。

グリッドの数は、

1. グリッド間隔と資金配分

グリッド取引の中心的な機能は、複数のグリッド間隔を設定して各間隔に資金を割り当てることです。グリッドの数を決定するときは、まず各グリッド間の間隔と各グリッド内の資金の量を計算する必要があります。グリッド数の設定は、各グリッド内の資金の量に影響するだけでなく、各グリッドの売買価格の範囲も決定します。

  • グリッド間隔: グリッドが密すぎると、取引機会は増えますが、各取引の資金量が少なくなり、総収益の上限が低くなる可能性があります。逆に、グリッドが疎すぎると、各取引の資金量が多くなりますが、取引頻度が低いため、利益機会を逃す可能性があります。
  • 資金配分: グリッド数を設定する際には、各グリッドに資金が分散しすぎて効果的に利益が得られないことがないように、資金の配分のバランスをとる必要があります。

2. 口座資金とリスク管理

アカウント資金はグリッドの数を決定する重要な要素です。アカウント資金が大きいほど、より多くのグリッドを設定できますが、アカウント資金が小さい場合は、資金の割り当てが分散しすぎて各グリッドの資金が少なくなり、効果的に利益を上げることができなくなるのを避けるために、グリッドの数に制限が必要です。

さらに、グリッド取引のリスク管理戦略では、グリッド数の設定も考慮する必要があります。特に市場が激しく変動している場合には、グリッドが多すぎると損失が大きくなる可能性があるため、過剰な取引を避けるためにグリッドの数を合理的に制御する必要があります。

グリッド取引戦略の実装

グリッド取引戦略の実際の適用において、特にグリッド数と収益率のバランスを最適化する場合、Datadata プラットフォームの DQL (Datadata Query Language) は大きな柔軟性を提供します。 DQL は、効率的なデータ クエリ、処理、分析をサポートするだけでなく、トレーダーがグリッド取引戦略のパフォーマンスをシミュレートおよびバックテストして、最も適切なグリッド番号やその他のパラメーター構成を見つけるのにも役立ちます。

DQL を使用すると、複数の取引所 (Binance など) から過去の K ライン データを簡単に取得し、このデータに基づいてグリッド取引戦略を調整できます。このようにして、さまざまな市場環境や特定の通貨のボラティリティに応じて、最適なグリッド取引戦略を正確にスクリーニングすることができます。

1. データを取得する

グリッド取引戦略のバックテストを開始する前に、まず対象通貨の市場データを取得する必要があります。以下は、データベースから指定された通貨の K ライン データを照会するためのコードです。

# 获取目标币种的K线数据
data = query("select * from klines.spot_1d where Exchange = 'Binance' and Symbol = '???_usdt' order by Time")

解説:

  • データベースを照会することで、特定の通貨の値を取得できます (例:???_usdt)をBinance取引プラットフォームで確認できます(時間、始値、最高値、最低値、終値など)。これにより、戦略実行のための基本データが提供されます。

2. グリッド戦略機能

グリッド取引戦略の中核は、事前に設定されたグリッド数量と価格範囲を使用して取引することです。具体的な手順は次のとおりです。

  1. グリッド間隔(ギャップ)とグリッドあたりの取引額(想定額)を計算する

    • グリッド間隔(ギャップ): 市場における最高価格と最低価格の比率に基づいて計算されます。式は次のとおりです。 [ \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}} ]

  2. グリッドの開始価格と終了価格

    • 各グリッドの開始価格と終了価格は、グリッド間隔に基づいて動的に計算されます。例えば、最初のグリッドの開始価格は最低価格であり、2番目のグリッドの開始価格は最低価格にexp(gap)、 等々。
  3. トレーディング業務

    • 開店条件: 価格が特定のグリッドの開始価格まで下がると、買い操作が実行されます。
    • 平仓条件: あるグリッドの終値まで価格が上昇すると、売り操作が実行されます。
  4. 取引手数料: 各取引の手数料が 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

3. バックテストを実行する

対象通貨には、「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

4. 実験結果の分析

さまざまなグリッド番号構成でバックテストを行った結果、次の結果が得られました。

分析:

  • グリッドの数が増えると、純利益は最初は増加し、その後は減少する傾向を示します。グリッド数が15のとき、純利益は最大値に達します。グリッド数が増加し続けたため、純利益は減少しました。
  • 最小および最大の収益の変動は純収益の傾向と似ており、グリッド番号の選択が収益に重要な影響を与えることを示しています。

要約する

グリッドの数を適切に設定することは、グリッド取引戦略において重要なタスクです。グリッドの数を最適化することで、グリッド取引戦略の利益パフォーマンスを効果的に向上させ、リスクをより適切に管理することができます。この記事では、グリッド番号の設定を分析し、具体的な計算方法とサンプルコードを提供し、グリッド取引戦略を最適化し、戦略の安定性と収益性を向上させることに貢献したいと考えています。

注記: この記事のグリッドバックテストコードはZhihu Da Shenから引用したものです。 Halcyon、ソースコードの説明については記事を参照してくださいアルゴリズムトレード実践日記(XVIII) - グリッドトレードの詳細:グリッド番号と長期リターンの関係