3
フォロー
1444
フォロワー

永久契約グリッド戦略パラメータ最適化の詳細な説明

作成日:: 2023-12-08 17:00:38, 更新日:: 2023-12-14 17:07:42
comments   1
hits   2862

永久契約グリッド戦略パラメータ最適化の詳細な説明

永久グリッド戦略は、プラットフォーム上で人気のある古典的な戦略です。スポットグリッドと比較すると、コインを保有する必要がなく、レバレッジを加えることができるため、スポットグリッドよりもはるかに便利です。しかし、Inventor Quantitative Platformで直接バックテストを行うことはできないため、通貨のスクリーニングやパラメータの最適化の決定には役立ちません。この記事では、データ収集、バックテストフレームワーク、バックテスト関数、パラメータの最適化など、Pythonバックテストの完全なプロセスを紹介します。など。jupyter ノートブックで自分で試すことができます。

データ収集

一般的に、Kラインデータで十分です。正確さのために、Kライン期間は短いほど良いです。ただし、バックテスト時間とデータ量はバランスが取れている必要があります。この記事では、バックテストに過去2年間の5分データを使用しています。最終データ量が 200,000 行を超えます。DYDX を選択します。もちろん、特定の通貨とKライン期間は、ご自身の興味に応じて選択できます。

import requests
from datetime import date,datetime
import time
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import requests, zipfile, io
%matplotlib inline

def GetKlines(symbol='BTC',start='2020-8-10',end='2021-8-10',period='1h'):
    Klines = []
    start_time = int(time.mktime(datetime.strptime(start, "%Y-%m-%d").timetuple()))*1000
    end_time = int(time.mktime(datetime.strptime(end, "%Y-%m-%d").timetuple()))*1000
    while start_time < end_time:
        res = requests.get('https://fapi.binance.com/fapi/v1/klines?symbol=%sUSDT&interval=%s&startTime=%s&limit=1000'%(symbol,period,start_time))
        res_list = res.json()
        Klines += res_list
        start_time = res_list[-1][0]
    return pd.DataFrame(Klines,columns=['time','open','high','low','close','amount','end_time','volume','count','buy_amount','buy_volume','null']).astype('float')

df = GetKlines(symbol='DYDX',start='2022-1-1',end='2023-12-7',period='5m')
df = df.drop_duplicates()

バックテストフレームワーク

バックテストでは、以前から一般的に使用されていた、シンプルで使いやすい USDT 永久契約の複数通貨をサポートするフレームワークを引き続き使用します。

class Exchange:
    
    def __init__(self, trade_symbols, fee=0.0004, initial_balance=10000):
        self.initial_balance = initial_balance #初始的资产
        self.fee = fee
        self.trade_symbols = trade_symbols
        self.account = {'USDT':{'realised_profit':0, 'unrealised_profit':0, 'total':initial_balance, 'fee':0}}
        for symbol in trade_symbols:
            self.account[symbol] = {'amount':0, 'hold_price':0, 'value':0, 'price':0, 'realised_profit':0,'unrealised_profit':0,'fee':0}
            
    def Trade(self, symbol, direction, price, amount):
        
        cover_amount = 0 if direction*self.account[symbol]['amount'] >=0 else min(abs(self.account[symbol]['amount']), amount)
        open_amount = amount - cover_amount
        self.account['USDT']['realised_profit'] -= price*amount*self.fee #扣除手续费
        self.account['USDT']['fee'] += price*amount*self.fee
        self.account[symbol]['fee'] += price*amount*self.fee

        if cover_amount > 0: #先平仓
            self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount  #利润
            self.account[symbol]['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount
            
            self.account[symbol]['amount'] -= -direction*cover_amount
            self.account[symbol]['hold_price'] = 0 if self.account[symbol]['amount'] == 0 else self.account[symbol]['hold_price']
            
        if open_amount > 0:
            total_cost = self.account[symbol]['hold_price']*direction*self.account[symbol]['amount'] + price*open_amount
            total_amount = direction*self.account[symbol]['amount']+open_amount
            
            self.account[symbol]['hold_price'] = total_cost/total_amount
            self.account[symbol]['amount'] += direction*open_amount
                    
    
    def Buy(self, symbol, price, amount):
        self.Trade(symbol, 1, price, amount)
        
    def Sell(self, symbol, price, amount):
        self.Trade(symbol, -1, price, amount)
        
    def Update(self, close_price): #对资产进行更新
        self.account['USDT']['unrealised_profit'] = 0
        for symbol in self.trade_symbols:
            self.account[symbol]['unrealised_profit'] = (close_price[symbol] - self.account[symbol]['hold_price'])*self.account[symbol]['amount']
            self.account[symbol]['price'] = close_price[symbol]
            self.account[symbol]['value'] = abs(self.account[symbol]['amount'])*close_price[symbol]
            self.account['USDT']['unrealised_profit'] += self.account[symbol]['unrealised_profit']
        self.account['USDT']['total'] = round(self.account['USDT']['realised_profit'] + self.initial_balance + self.account['USDT']['unrealised_profit'],6)

グリッドバックテスト機能

グリッド戦略の原理は非常にシンプルです。価格が上昇したら売り、価格が下落したら買うのです。これには初期価格、グリッド間隔、取引額という 3 つの特定のパラメータが関係します。 DYDXの市場変動は非常に大きく、当初の8.6Uから1Uに下落し、最近の強気市場では3Uまで上昇しました。戦略のデフォルトの初期価格は8.6Uであり、グリッドにとって非常に不利です。戦略ですが、デフォルトのパラメータバックテストでは、2年間の合計利益は9200Uで、一時は7500Uの損失がありました。 永久契約グリッド戦略パラメータ最適化の詳細な説明

symbol = 'DYDX'
value = 100
pct = 0.01

def Grid(fee=0.0002, value=100, pct=0.01, init = df.close[0]):
    e = Exchange([symbol], fee=0.0002, initial_balance=10000)
    init_price = init
    res_list = [] #用于储存中间结果
    for row in df.iterrows():
        kline = row[1] #这样会测一根K线只会产生一个买单或一个卖单,不是特别精确
        buy_price = (value / pct - value) / ((value / pct) / init_price + e.account[symbol]['amount']) #买单价格,由于是挂单成交,也是最终的撮合价格
        sell_price = (value / pct + value) / ((value / pct) / init_price + e.account[symbol]['amount'])
        if kline.low < buy_price: #K线最低价低于当前挂单价,买单成交
            e.Buy(symbol,buy_price,value/buy_price)
        if kline.high > sell_price:
            e.Sell(symbol,sell_price,value/sell_price)
        e.Update({symbol:kline.close})
        res_list.append([kline.time, kline.close, e.account[symbol]['amount'], e.account['USDT']['total']-e.initial_balance,e.account['USDT']['fee'] ])
    res = pd.DataFrame(data=res_list, columns=['time','price','amount','profit', 'fee'])
    res.index = pd.to_datetime(res.time,unit='ms')
    return res

永久契約グリッド戦略パラメータ最適化の詳細な説明

初値の影響

初期価格の設定は、戦略の初期ポジションに影響します。現在のバックテストのデフォルトの初期価格は、起動時の初期価格です。つまり、起動時にはポジションは保持されません。グリッド戦略は、価格が初期レベルに戻ったときにすべての利益を実現することがわかっているので、戦略が開始時に将来の市場を正しく予測できれば、利益が大幅に増加します。ここでは、初期価格を 3U に設定してバックテストを行います。最終的な最大ドローダウンは9200U、最終利益は13372Uでした。最終戦略ではポジションを保持しません。この利益はすべてボラティリティ利益であり、デフォルトパラメータの利益とこの利益の差額が最終価格の不正確な判断によって生じたポジション損失です。

ただし、初期価格が 3U に設定されている場合、この戦略は最初にショートになり、多数のショート ポジションを保持します。この例では、17,000 U のショート ポジションが直接保持されるため、より大きなリスクに直面します。

永久契約グリッド戦略パラメータ最適化の詳細な説明

グリッド間隔設定

グリッド間隔は、保留中の注文間の距離を決定します。当然、間隔が狭いほど、取引の頻度が高くなり、1 回の取引の利益は低くなり、手数料は高くなります。しかし、グリッド間隔が小さくなり、グリッド値が変わらない場合、価格が変動すると合計ポジションが増加し、直面するリスクがまったく異なることに注意してください。したがって、グリッド間隔の効果をバックテストするには、グリッド値を変換する必要があります。

バックテストでは 5mK ラインのデータが使用され、K ラインでは 1 つのトランザクションのみが実行されます。これは明らかに現実と一致していません。特にデジタル通貨のボラティリティは非常に大きいためです。間隔が狭いと、実際の取引と比較して、バックテストで多くの取引を見逃すことになります。間隔が広い場合にのみ、参照値があります。このバックテストのメカニズムでは、導き出された結論は正確ではありません。ティックレベルの注文フロー データのバックテストにより、最適なグリッド間隔は 0.005 ~ 0.01 であることがわかりました。

for p in [0.0005, 0.001 ,0.002 ,0.005, 0.01, 0.02, 0.05]:
    res = Grid( fee=0.0002, value=value*p/0.01, pct=p, init =3)
    print(p, round(min(res['profit']),0), round(res['profit'][-1],0), round(res['fee'][-1],0))
    
0.0005 -8378.0 144.0 237.0
0.001 -9323.0 1031.0 465.0
0.002 -9306.0 3606.0 738.0
0.005 -9267.0 9457.0 781.0
0.01 -9228.0 13375.0 550.0
0.02 -9183.0 15212.0 309.0
0.05 -9037.0 16263.0 131.0

グリッド取引額

前述のように、ボラティリティが同じ場合、保有価値が大きいほどリスク比例法は高くなりますが、急激な下落でない限り、グリッド間隔の1%と合わせて総資金の1%ほとんどの市場状況に対応できるはずです。この DYDX の例では、ほぼ 90% の下落によってマージン コールも発生しました。ただし、DYDXは主に下落することに注意してください。下落すると、グリッド戦略はロングになり、最大下落率は100%になります。ただし、上昇には制限がなく、リスクははるかに高くなります。したがって、グリッド戦略では、ユーザーが潜在性があると考える通貨を選択し、ロングのみを行うことを推奨しています。

変数回帰価格

回帰価格は初期価格です。現在の価格と初期価格の差とグリッドサイズによって、どれだけのポジションを保持すべきかが決まります。回帰価格が現在の価格よりも高く設定されている場合、グリッド戦略はロングになり、逆に。デフォルトの回帰価格は、戦略が開始された価格です。リスクを軽減するために、ロングオンリーグリッドを使用することをお勧めします。自然なアイデアは、価格が上昇しても調整せずにロングポジションを保持できるように回帰価格を変更できるかどうかです。あなた自身。今年のBTC市場を例にとると、年初は15,000だったのが年末には43,000に上昇しました。年初からグリッド戦略を実行すると、デフォルトのリターン価格は15,000で、ロングとショートの両方の取引を行います。具体的なリターンは下の図のとおりです。BTCが下落するにつれて、ずっと損失が発生します。上昇します。ロングオンリーモードが正しく設定されていない場合でも、ポジションを保持せずに価格がすぐに制限を超える可能性があります。 永久契約グリッド戦略パラメータ最適化の詳細な説明

まず、戦略が開始されると、回帰価格は起動時の価格の1.6倍に設定されます。このように、グリッド戦略は価格が1.6倍から現在の価格に下落しているとみなし、ロングポジションを保持し始めます。この部分の価格差によってポジションが発生します。後続の価格が /1.6 を超えると、初期価格がリセットされ、少なくとも 60% の差が常にロング ポジションに利用できるようになります。バックテストの結果は次のとおりです。 永久契約グリッド戦略パラメータ最適化の詳細な説明

もちろん、市場に対してより楽観的であれば、この比率をより大きな値に設定することができ、最終的な利益はそれに応じて増加します。もちろん、市場が下落した場合、この設定ではポジションを保持するリスクも増加します。