資源の読み込みに... 荷物...

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

作者: リン・ハーン小草作成日: 2024-07-05 16:23:42,更新日: 2024-11-05 17:42:06

img

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

前言

最近,BUEの定量化日記では,マイナス関連通貨を利用して通貨を取引し,価格差突破によって取引を開始し,利益を得ることが言及されている. デジタル通貨は基本的にはマイナス関連であり,マイナス関連は少数通貨で,しばしば特殊な市場がある. 例えば,以前のMEMEコインの独立市場は,大盘の動向を全く追わない. これらの通貨をフィルタリングし,突破後に多く行う. この方法は特定の状況下で利益を得ることができる. しかし,定量化取引の分野では,最も一般的な関連利用は正行性配列取引であり,この戦略を簡潔に説明します.

デジタル通貨配列取引は,価格偏差から利益を得るために,両者との高度な関連性のあるデジタル通貨の永続契約を同時に買ったり売ったりすることで,統計的利潤に基づいた取引戦略である.この記事では,この戦略の原理,収益メカニズム,コイン種をシフトする方法,潜在的なリスク,および改善方法について詳細に説明し,いくつかの実用的なPythonコードの例を提供します.

戦略の原理

配列取引戦略は,2つのデジタル通貨の価格の間の歴史的関連性に依存する. 二つの通貨の価格が強い関連性を示すとき,その価格動向はほぼ同期する. もし,ある時点で両者の価格比率が著しく偏った場合,これは一時的な異常とみなされ,価格が正常水準に戻る傾向がある. デジタル通貨市場は高度な連動性があり,主要なデジタル通貨であるビットコインが大きく波動するときに,他のデジタル通貨の連動反応を誘発することが多い. いくつかの通貨は,同じ投資機関,同じ取引者,同じ競争の理由によって非常に顕著な正則的な関連性があり,持続可能である.

通貨Aと通貨Bが高い価格相関性を持っていると仮定する.ある時点でA/Bの価格比率が平均値である.ある時点でA/Bの価格比率が0.001以上,すなわち1.001以上上昇した場合,以下のように取引することができます.

利潤の鍵は,価格偏差が正常に戻ると差利回しである.価格偏差は通常短期間であるため,トレーダーは価格が平均値に戻ると平衡し,利益を得て差利を稼ぐことができる.

準備データ

データベースを導入する

これらのコードは直接利用可能で,Anancodaをダウンロードしてjupyer notebookでデビューすることが望ましい.

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の主な機能は,ビットコイン取引所から指定された取引の永続契約の歴史的な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ヶ月間の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に近づくほど,関係性が強くなる.
  • -12つの変数が常に逆転していることを表す.−1に近づくほど負の関連性が強いことを表す.
  • 0ワイヤレス関係を示し,2つの変数間には直線的な関係がない.

ピルソン相関系数は,両変数の共関差と標準差を計算して相関関係を決定する.式は以下のとおりである.

グラフの表は,x,yの表で,x,yの表は,x,yの表で

その中には:

  • (\rho_{X,Y}) は変数 (X) と (Y) のピルソン相関数である.
  • (\text{cov}(X,Y) は, (X) と (Y) の共角差である.
  • (\sigma_X) と (\sigma_Y) はそれぞれ, (X) と (Y) の標準差である.

もちろん,計算方法に関心なく,Pythonの1行コードを使用してすべての通貨の関連性を計算できます. この図は関連性熱線図を示しています. 赤の代表は正関係,青の代表は負関係,色が深ければ深くなるほど関連性が強いです.

img

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初期残高は1万ドルで,取引手数料は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つの部分に分割し,前回の計算関連性に基づいて,後の再テスト取引の結果は,少し悪いが良好です. ユーザの自己の練習検証を残します.

img

潜在的リスクと改善方法

配列取引戦略は理論上有利であるものの,実用操作ではいくつかのリスクがあります:通貨間の関連性が時間の経過とともに変化し,戦略が失敗する可能性があります. 極端な市場条件下では,価格偏差が激化し,大きな損失を引き起こす可能性があります. 特定の通貨の流動性が低く,取引が実行に困難またはコストが増加する可能性があります. 頻繁な取引による手続費が利益を蝕む可能性があります.

リスクを軽減し,戦略の安定性を高めるために,以下の改善策を検討することができる: 通貨間の関連性を定期的に再計算し,取引対を適時に調整する; ストップ損失とストップピークを設定し,単一の取引の最大損失を制御する; 同時に複数の通貨対を取引し,リスクを分散する.

結論

デジタル通貨配列取引戦略は,通貨価格の関連性を利用し,価格偏差時に利息操作を行い,利益を得ることを目的とする.この戦略は理論上高い可行性を有する.その後,この戦略に基づいたシンプルなリアルタイムの戦略ソースコードがリリースされる.より多くの質問やさらなる議論が必要な場合は,いつでも連絡してください.


もっと

77924998オープンソースは研究に値するものです.

豆888張総裁は - ハハハ!