3
フォロー
1444
フォロワー

デジタル通貨ペア取引戦略の詳細な説明

作成日:: 2024-07-05 16:23:42, 更新日:: 2024-11-05 17:42:06
comments   3
hits   5800

デジタル通貨ペア取引戦略の詳細な説明

デジタル通貨ペア取引戦略の詳細な説明

導入

最近、Buu の定量日記を見ましたが、そこには、相関が逆の通貨を使って通貨を選択し、価格差の突破に基づいて利益を上げるためにポジションを開くことができると書かれていました。デジタル通貨は基本的に正の相関関係にあり、負の相関関係にある通貨はごくわずかです。それらは、少し前のMEMEコインの独立した市場状況のように、市場のトレンドにまったく従わない特別な市場状況になることがよくあります。これらの通貨をブレイクスルー後にロングすると、この方法は特定の市場状況下で利益を上げることができます。しかし、定量取引の分野で最も一般的な方法は、ペア取引に正の相関関係を使用することです。この記事では、この戦略について簡単に紹介します。

暗号通貨ペア取引は、統計的裁定取引に基づく取引戦略であり、相関性の高い 2 つの暗号通貨の永久契約を同時に売買することで、価格の偏差から利益を得ようとします。この記事では、戦略の原則、利益のメカニズム、通貨のスクリーニング方法、潜在的なリスクと改善方法を紹介し、実用的な Python コードの例をいくつか示します。

戦略原則

ペア取引戦略は、2 つの暗号通貨の価格間の過去の相関関係に依存します。 2 つの通貨の相関が強い場合、その価格はほぼ同期して動きます。ある瞬間に両者の価格比率が大きく乖離した場合、これは一時的な異常であり、価格は正常レベルに戻る傾向があると考えられます。デジタル通貨市場は高度に相互接続されています。主要なデジタル通貨(ビットコインなど)が大きな変動を経験すると、通常、他のデジタル通貨の間で連鎖反応が引き起こされます。一部の通貨は非常に明白な正の相関関係があり、同じ投資機関、同じマーケットメーカー、同じトラックに属しているため、その相関関係が維持される可能性があります。一部の通貨は負の相関関係にありますが、負の相関関係にある通貨は少なく、すべてが全体的な市場動向の影響を受けるため、一貫した市場動向を示すことがよくあります。

コイン A とコイン B の価格相関が高いと仮定します。ある瞬間、A/B 価格比の平均値は 1 です。ある瞬間に、A/B価格比が0.001以上、つまり1.001以上増加から逸脱した場合、次の方法で取引することができます:Bでロングポジションを開き、Aでショートポジションを開きます。 。逆に、A/B 価格比率が 0.999 未満の場合は、A でロング ポジションを開き、B でショート ポジションを開きます。

収益性の鍵は、価格が逸脱して正常に戻ったときに得られる価格差の利益にあります。価格の変動は通常短期間で終わるため、トレーダーは価格が平均値に戻ったときにポジションをクローズし、その差額から利益を得ることができます。

データを準備する

対応するライブラリをインポートする

これらのコードは直接使用することもできますが、Anancoda をダウンロードして Jupyer ノートブックでデバッグするのが最適です。一般的に使用されるデータ分析用のパッケージが直接含まれています。

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

取引されているすべての取引ペアを取得する

Info = requests.get('https://fapi.binance.com/fapi/v1/exchangeInfo')
b_symbols = [s['symbol'] for s in Info.json()['symbols'] if s['contractType'] == 'PERPETUAL' and s['status'] == 'TRADING' and s['quoteAsset'] == 'USDT']
b_symbols = list(filter(lambda x: x[-4:] == 'USDT', [s.split('_')[0] for s in b_symbols]))
b_symbols = [x[:-4] for x in b_symbols]
print(b_symbols) # 获取所有的正在交易的交易对

Kライン関数をダウンロード

GetKlines 関数の主な機能は、Binance 取引所から指定された取引ペアの永久契約の履歴 K ライン データを取得し、このデータを Pandas DataFrame に保存することです。 K ライン データには、始値、最高値、最低値、終値、取引量などの情報が含まれます。今回は主に終値データを利用します。

def GetKlines(symbol='BTCUSDT',start='2020-8-10',end='2024-7-01',period='1h',base='fapi',v = 'v1'):
    Klines = []
    start_time = int(time.mktime(datetime.strptime(start, "%Y-%m-%d").timetuple()))*1000 + 8*60*60*1000
    end_time =  min(int(time.mktime(datetime.strptime(end, "%Y-%m-%d").timetuple()))*1000 + 8*60*60*1000,time.time()*1000)
    intervel_map = {'m':60*1000,'h':60*60*1000,'d':24*60*60*1000}
    while start_time < end_time:
        time.sleep(0.3)
        mid_time = start_time+1000*int(period[:-1])*intervel_map[period[-1]]
        url = 'https://'+base+'.binance.com/'+base+'/'+v+'/klines?symbol=%s&interval=%s&startTime=%s&endTime=%s&limit=1000'%(symbol,period,start_time,mid_time)
        res = requests.get(url)
        res_list = res.json()
        if type(res_list) == list and len(res_list) > 0:
            start_time = res_list[-1][0]+int(period[:-1])*intervel_map[period[-1]]
            Klines += res_list
        if type(res_list) == list and len(res_list) == 0:
            start_time = start_time+1000*int(period[:-1])*intervel_map[period[-1]]
        if mid_time >= end_time:
            break
    df = pd.DataFrame(Klines,columns=['time','open','high','low','close','amount','end_time','volume','count','buy_amount','buy_volume','null']).astype('float')
    df.index = pd.to_datetime(df.time,unit='ms')
    return df

データをダウンロード

データ量が比較的多いため、ダウンロードを高速化するために、過去 3 か月分の 1 時間ごとの K ライン データのみを取得しました。 df_closeにはすべての通貨の終値データが含まれています

start_date = '2024-04-01'
end_date   = '2024-07-05'
period = '1h'
df_dict = {}

for symbol in b_symbols:   
    print(symbol)
    if symbol in df_dict.keys():
        continue
    df_s = GetKlines(symbol=symbol+'USDT',start=start_date,end=end_date,period=period)
    if not df_s.empty:
        df_dict[symbol] = df_s
df_close = pd.DataFrame(index=pd.date_range(start=start_date, end=end_date, freq=period),columns=df_dict.keys())
for symbol in symbols:
    df_close[symbol] = df_dict[symbol].close
df_close = df_close.dropna(how='all')

バックテストエンジン

次のバックテストのExchangeオブジェクトを定義します

class Exchange:
    def __init__(self, trade_symbols, fee=0.0002, 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, 'leverage':0, 'hold':0, 'long':0, 'short':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
        self.account['USDT']['hold'] = 0
        self.account['USDT']['long'] = 0
        self.account['USDT']['short'] = 0
        for symbol in self.trade_symbols:
            if not np.isnan(close_price[symbol]):
                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'] = self.account[symbol]['amount']*close_price[symbol]
                if self.account[symbol]['amount'] > 0:
                    self.account['USDT']['long'] += self.account[symbol]['value']
                if self.account[symbol]['amount'] < 0:
                    self.account['USDT']['short'] += self.account[symbol]['value']
                self.account['USDT']['hold'] += abs(self.account[symbol]['value'])
                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)
        self.account['USDT']['leverage'] = round(self.account['USDT']['hold']/self.account['USDT']['total'],3)

通貨をフィルタリングするための相関分析

相関計算は、2 つの変数間の線形関係を測定するために使用される統計手法です。最も一般的に使用される相関計算方法は、ピアソン相関係数です。以下に相関計算の原理、計算式、実装方法を示します。ピアソン相関係数は、2 つの変数間の線形関係を測定するために使用され、その値の範囲は -1 から 1 の間です。

  • 1 2 つの変数が常に同期して変化する完全な正の相関関係を示します。 1 つの変数が増加すると、他の変数も比例して増加します。 1 に近いほど相関が強くなります。
  • -1 2 つの変数が常に反対方向に変化する完全な負の相関を示します。 -1 に近いほど、負の相関が強くなります。
  • 0 線形相関がないことを示します。2 つの変数の間に直線関係はありません。

ピアソン相関係数は、共分散と標準偏差を計算することで、2 つの変数間の相関関係を決定します。式は次のとおりです。

[ \rho_{X,Y} = \frac{\text{cov}(X,Y)}{\sigma_X \sigma_Y} ]

で:

  • ( \rho_{X,Y} ) 変数である( X ) そして ( Y ) ピアソン相関係数。
  • ( \text{cov}(X,Y) ) はい ( X ) そして ( Y ) の共分散。
  • ( \sigma_X ) そして ( \sigma_Y ) 彼らです( X ) そして ( Y ) の標準偏差。

もちろん、計算方法についてはあまり心配する必要はありません。Python コードを 1 行書くだけで、すべての通貨の相関関係を計算できます。この図は相関ヒートマップを示しています。赤は正の相関、青は負の相関を表し、色が濃いほど相関が強いことを示します。広い範囲が濃い赤色になっていることから、デジタル通貨の正の相関関係が非常に強いことがわかります。

デジタル通貨ペア取引戦略の詳細な説明

import seaborn as sns
corr = df_close.corr()
plt.figure(figsize=(20, 20))
sns.heatmap(corr, annot=False, cmap='coolwarm', vmin=-1, vmax=1)
plt.title('Correlation Heatmap of Cryptocurrency Closing Prices', fontsize=20);

相関関係に基づいて、最も関連性の高い上位 20 の通貨ペアが選択されます。結果は以下の通りです。相関関係は非常に強く、すべて 0.99 を超えています。

MANA     SAND     0.996562
ICX      ZIL      0.996000
STORJ    FLOW     0.994193
FLOW     SXP      0.993861
STORJ    SXP      0.993822
IOTA     ZIL      0.993204
         SAND     0.993095
KAVA     SAND     0.992303
ZIL      SXP      0.992285
         SAND     0.992103
DYDX     ZIL      0.992053
DENT     REEF     0.991789
RDNT     MANTA    0.991690
STMX     STORJ    0.991222
BIGTIME  ACE      0.990987
RDNT     HOOK     0.990718
IOST     GAS      0.990643
ZIL      HOOK     0.990576
MATIC    FLOW     0.990564
MANTA    HOOK     0.990563

対応するコードは次のとおりです。

corr_pairs = corr.unstack()

# 移除自身相关性(即对角线上的值)
corr_pairs = corr_pairs[corr_pairs != 1]

sorted_corr_pairs = corr_pairs.sort_values(kind="quicksort")

# 提取最相关和最不相关的前20个币种对
most_correlated = sorted_corr_pairs.tail(40)[::-2]

print("最相关的前20个币种对:")
print(most_correlated)

バックテスト検証

具体的なバックテストコードは以下の通りです。デモ戦略は、2 つの暗号通貨 (IOTA と ZIL) の価格比率を観察し、この比率の変化に基づいて取引することに重点を置いています。具体的な手順は次のとおりです。

  1. 初期化

    • 取引ペアを定義します (pair_a = ‘IOTA’、pair_b = ‘ZIL’)。
    • 交換オブジェクトを作成するe初期残高は 10,000 ドル、取引手数料は 0.02% です。
    • 初期平均価格比率の計算avg
    • 初期取引値を設定するvalue = 1000
  2. 価格データを反復的に処理する

    • 各時点の価格データを走査するdf_close
    • 現在の価格比率の平均からの偏差を計算しますdiff
    • 偏差に基づいて目標取引額を計算するaim_value0.01 の偏差ごとに 1 つの値を取引します。そして、現在の口座ポジションと価格状況に基づいて売買操作を決定します。
    • 偏差が大きすぎる場合は売りを実行するpair_a 購入するpair_b 操作する。
    • 偏差が小さすぎる場合は、買いを実行しますpair_a 売るpair_b 操作する。
  3. 調整平均

    • 平均価格比率を更新avg最新の価格比率を反映するためです。
  4. アカウントと記録の更新

    • 取引所口座のポジションと残高情報を更新します。
    • 各ステップで口座状況(総資産、保有高、取引手数料、ロングポジションとショートポジション)を記録し、res_list
  5. 結果出力

    • 意思 res_list データフレームに変換するres、さらなる分析とプレゼンテーションのために。
pair_a = 'IOTA'
pair_b = "ZIL"
e = Exchange([pair_a,pair_b], fee=0.0002, initial_balance=10000) #Exchange定义放在评论区
res_list = []
index_list = []
avg = df_close[pair_a][0] / df_close[pair_b][0]
value = 1000
for idx, row in df_close.iterrows():
    diff = (row[pair_a] / row[pair_b] - avg)/avg
    aim_value = -value * diff / 0.01
    if -aim_value + e.account[pair_a]['amount']*row[pair_a] > 0.5*value:
        e.Sell(pair_a,row[pair_a],(-aim_value + e.account[pair_a]['amount']*row[pair_a])/row[pair_a])
        e.Buy(pair_b,row[pair_b],(-aim_value - e.account[pair_b]['amount']*row[pair_b])/row[pair_b])
    if -aim_value + e.account[pair_a]['amount']*row[pair_a]  < -0.5*value:
        e.Buy(pair_a, row[pair_a],(aim_value - e.account[pair_a]['amount']*row[pair_a])/row[pair_a])
        e.Sell(pair_b, row[pair_b],(aim_value + e.account[pair_b]['amount']*row[pair_b])/row[pair_b])
    avg = 0.99*avg + 0.01*row[pair_a] / row[pair_b]
    index_list.append(idx)
    e.Update(row)
    res_list.append([e.account['USDT']['total'],e.account['USDT']['hold'],
                         e.account['USDT']['fee'],e.account['USDT']['long'],e.account['USDT']['short']])
res = pd.DataFrame(data=res_list, columns=['total','hold', 'fee', 'long', 'short'],index = index_list)
res['total'].plot(grid=True);

合計 4 つの通貨グループをバックテストし、結果は比較的理想的でした。現在の相関計算では将来のデータが使用されるため、あまり正確ではありません。また、この記事では、前部の計算された相関関係と後部のバックテストされたトランザクションに基づいて、データを 2 つの部分に分割します。結果は少し外れましたが、それでもかなり良かったです。検証はユーザー自身で行う必要があります。

デジタル通貨ペア取引戦略の詳細な説明

潜在的なリスクと改善方法

ペア取引戦略は理論上は利益を上げることができますが、実際の運用には依然としていくつかのリスクがあります。通貨間の相関関係は時間の経過とともに変化し、戦略が失敗する可能性があります。極端な市場状況では、価格の偏差が拡大し、大きな損失が発生する可能性があります。特定の通貨の流動性が低いと、取引の実行が困難になったり、コストが増加したりする可能性があります。また、頻繁な取引によって発生する手数料によって利益が損なわれる可能性があります。

リスクを軽減し、戦略の安定性を向上させるために、次の改善策を検討できます。通貨間の相関関係を定期的に再計算し、取引ペアを適時に調整する。ストップロスとテイクプロフィットポイントを設定して、単一取引の最大損失を制御する。リスクを分散するために複数の通貨ペアを取引します。

結論は

デジタル通貨ペア取引戦略は、通貨価格の相関関係を利用し、価格が逸脱したときに裁定取引を実行することで利益を達成します。この戦略は理論的には実現可能性が高い。この戦略に基づいたシンプルなリアルタイム戦略のソースコードは後日公開される予定です。さらにご質問がある場合や、さらに話し合いが必要な場合は、お気軽にご連絡ください。