3
Suivre
1444
Abonnés

Explication détaillée de la stratégie de trading de paires de devises numériques

Créé le: 2024-07-05 16:23:42, Mis à jour le: 2024-11-05 17:42:06
comments   3
hits   5807

Explication détaillée de la stratégie de trading de paires de devises numériques

Explication détaillée de la stratégie de trading de paires de devises numériques

introduction

J’ai récemment vu le journal quantitatif de Buu qui mentionnait que vous pouvez utiliser des devises corrélées négativement pour sélectionner des devises et ouvrir des positions pour réaliser des bénéfices en fonction des percées de différence de prix. Les monnaies numériques sont fondamentalement corrélées positivement, et seules quelques monnaies sont corrélées négativement. Elles ont souvent des conditions de marché particulières, telles que les conditions de marché indépendantes des pièces MEME il y a quelque temps, qui ne suivent pas du tout la tendance du marché. Filtrer ces devises et aller longtemps après la percée, cette méthode peut générer des bénéfices dans certaines conditions de marché. Cependant, la méthode la plus courante dans le domaine du trading quantitatif consiste à utiliser la corrélation positive pour le trading par paires. Cet article présente brièvement cette stratégie.

Le trading de paires de crypto-monnaies est une stratégie de trading basée sur l’arbitrage statistique, qui cherche à tirer profit des écarts de prix en achetant et en vendant simultanément deux contrats perpétuels de crypto-monnaies hautement corrélés. Cet article présentera les principes de la stratégie, le mécanisme de profit, la méthode de filtrage des devises, les risques potentiels et les moyens de l’améliorer, et fournira quelques exemples pratiques de code Python.

Principe de stratégie

Les stratégies de trading par paires s’appuient sur la corrélation historique entre les prix de deux crypto-monnaies. Lorsque deux devises sont fortement corrélées, leurs prix évoluent à peu près de manière synchronisée. Si à un moment donné le rapport des prix des deux s’écarte significativement, on peut considérer qu’il s’agit d’une anomalie temporaire et les prix auront tendance à revenir à des niveaux normaux. Le marché des devises numériques est fortement interconnecté. Lorsqu’une devise numérique majeure (comme le Bitcoin) subit des fluctuations importantes, cela déclenche généralement une réaction en chaîne parmi les autres devises numériques. Certaines devises peuvent avoir une corrélation positive très évidente, et cette corrélation peut être maintenue, car elles appartiennent aux mêmes institutions d’investissement, aux mêmes teneurs de marché et au même parcours. Certaines devises sont corrélées négativement, mais il existe moins de devises corrélées négativement et, comme elles sont toutes affectées par la tendance générale du marché, elles présentent souvent des tendances de marché cohérentes.

Supposons que la pièce A et la pièce B aient une forte corrélation de prix. À un moment donné, la valeur moyenne du ratio de prix A/B est de 1. Si à un certain moment, le rapport de prix A/B s’écarte de la hausse de plus de 0,001, c’est-à-dire de plus de 1,001, alors vous pouvez négocier de la manière suivante : ouvrir une position longue sur B et ouvrir une position courte sur A . Au contraire, lorsque le ratio de prix A/B est inférieur à 0,999 : ouvrez une position longue sur A et une position courte sur B.

La clé de la rentabilité réside dans les gains de différence de prix lorsque les prix s’écartent et reviennent à la normale. Étant donné que les écarts de prix sont généralement de courte durée, les traders peuvent clôturer leurs positions lorsque les prix reviennent à la moyenne et profiter de la différence.

Préparer les données

Importer la bibliothèque correspondante

Ces codes peuvent être utilisés directement, mais il est préférable de télécharger Anancoda et de le déboguer dans un notebook Jupyer. Inclut directement des packages pour l’analyse de données couramment utilisées.

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

Obtenez toutes les paires de trading en cours de négociation

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) # 获取所有的正在交易的交易对

Télécharger la fonction K-line

La fonction principale de la fonction GetKlines est d’obtenir les données historiques de la ligne K du contrat perpétuel de la paire de trading spécifiée auprès de la bourse Binance et de stocker ces données dans un Pandas DataFrame. Les données K-line incluent le prix d’ouverture, le prix le plus élevé, le prix le plus bas, le prix de clôture, le volume des transactions et d’autres informations. Cette fois, nous utilisons principalement les données du cours de clôture.

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

Télécharger les données

La quantité de données est relativement importante. Afin de pouvoir télécharger plus rapidement, seules les données horaires de la ligne K des trois derniers mois ont été obtenues. df_close contient les données de cours de clôture pour toutes les devises

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')

Moteur de backtesting

Définit un objet Exchange pour le backtest suivant

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)

Analyse de corrélation pour filtrer les devises

Le calcul de corrélation est une méthode statistique utilisée pour mesurer la relation linéaire entre deux variables. La méthode de calcul de corrélation la plus couramment utilisée est le coefficient de corrélation de Pearson. Vous trouverez ci-dessous les principes, les formules et les méthodes de mise en œuvre pour le calcul de corrélation. Le coefficient de corrélation de Pearson est utilisé pour mesurer la relation linéaire entre deux variables, et sa plage de valeurs est comprise entre -1 et 1 :

  • 1 Indique une corrélation positive parfaite, où les deux variables changent toujours de manière synchrone. Lorsqu’une variable augmente, l’autre variable augmente également proportionnellement. Plus il est proche de 1, plus la corrélation est forte.
  • -1 Indique une corrélation négative parfaite, où les deux variables changent toujours dans des directions opposées. Plus il est proche de -1, plus la corrélation négative est forte.
  • 0 Indique l’absence de corrélation linéaire, il n’y a pas de relation linéaire entre les deux variables.

Le coefficient de corrélation de Pearson détermine la corrélation entre deux variables en calculant leur covariance et leur écart type. La formule est la suivante :

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

dans:

  • ( \rho_{X,Y} ) est une variable( X ) et ( Y ) Le coefficient de corrélation de Pearson.
  • ( \text{cov}(X,Y) ) Oui ( X ) et ( Y ) La covariance de .
  • ( \sigma_X ) et ( \sigma_Y ) Ils sont( X ) et ( Y ) L’écart type de .

Bien sûr, vous n’avez pas à vous soucier outre mesure de la manière dont elle est calculée. Vous pouvez calculer la corrélation de toutes les devises en utilisant une seule ligne de code Python. L’image montre une carte thermique de corrélation. Le rouge représente la corrélation positive, le bleu représente la corrélation négative et plus la couleur est foncée, plus la corrélation est forte. On peut voir que de grandes zones sont rouge foncé, donc la corrélation positive de la monnaie numérique est très forte.

Explication détaillée de la stratégie de trading de paires de devises numériques

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);

Sur la base de la corrélation, les 20 paires de devises les plus pertinentes sont sélectionnées. Les résultats sont les suivants. Leurs corrélations sont très fortes, toutes supérieures à 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

Le code correspondant est le suivant :

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)

Vérification des backtests

Le code de backtest spécifique est le suivant. La stratégie de démonstration se concentre sur l’observation du rapport de prix de deux crypto-monnaies (IOTA et ZIL) et sur le trading en fonction des variations de ce rapport. Les étapes spécifiques sont les suivantes :

  1. initialisation

    • Définir les paires de trading (pair_a = ‘IOTA’, pair_b = ‘ZIL’).
    • Créer un objet d’échangee, le solde initial est de 10 000 $ et les frais de transaction sont de 0,02 %.
    • Calcul du ratio de prix moyen initialavg
    • Définir une valeur de transaction initialevalue = 1000
  2. Traiter de manière itérative les données de prix

    • Parcourez les données de prix à chaque instantdf_close
    • Calcule l’écart du ratio des prix actuels par rapport à la moyennediff
    • Calculer la valeur de transaction cible en fonction de l’écartaim_value, pour chaque écart de 0,01, échangez une valeur. Et décidez des opérations d’achat et de vente en fonction des positions courantes du compte et des conditions de prix.
    • Si l’écart est trop important, exécutez une ventepair_a et acheterpair_b fonctionner.
    • Si l’écart est trop faible, exécutez un achatpair_a et vendrepair_b fonctionner.
  3. Moyenne ajustée

    • Rapport de prix moyen mis à jouravg, afin de refléter le dernier rapport de prix.
  4. Mise à jour des comptes et des enregistrements

    • Mettre à jour les informations de position et de solde du compte d’échange.
    • Enregistrez l’état du compte à chaque étape (actifs totaux, avoirs, frais de transaction, positions longues et courtes) pourres_list
  5. Résultat de sortie

    • Volonté res_list Convertir en dataframeres, pour une analyse et une présentation plus approfondies.
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);

Au total, 4 groupes de devises ont été rétro-testés et les résultats ont été relativement idéaux. Les calculs de corrélation actuels utilisent des données futures, ils ne sont donc pas très précis. Cet article divise également les données en deux parties, en fonction de la corrélation calculée à l’avant et des transactions backtestées à l’arrière. Les résultats étaient un peu décevants mais toujours assez bons. Il appartient à l’utilisateur d’exercer la vérification.

Explication détaillée de la stratégie de trading de paires de devises numériques

Risques potentiels et moyens d’amélioration

Bien que la stratégie de trading par paires puisse être rentable en théorie, elle comporte néanmoins certains risques dans la pratique : la corrélation entre les devises peut changer au fil du temps, entraînant l’échec de la stratégie ; dans des conditions de marché extrêmes, les écarts de prix peuvent augmenter, entraînant des pertes importantes ; la faible liquidité de certaines devises peut rendre les transactions difficiles à exécuter ou augmenter les coûts ; les frais générés par les transactions fréquentes peuvent éroder les bénéfices.

Pour réduire le risque et améliorer la stabilité de la stratégie, les mesures d’amélioration suivantes peuvent être envisagées : recalculer régulièrement la corrélation entre les devises et ajuster les paires de trading dans le temps ; définir des points de stop loss et de take profit pour contrôler la perte maximale d’une seule transaction ; échangez plusieurs paires de pièces pour diversifier les risques.

en conclusion

La stratégie de trading de paires de devises numériques permet de réaliser des bénéfices en tirant parti de la corrélation entre les prix des devises et en effectuant des opérations d’arbitrage lorsque les prix s’écartent. Cette stratégie présente une faisabilité théorique élevée. Un code source de stratégie en temps réel simple basé sur cette stratégie sera publié ultérieurement. Si vous avez d’autres questions ou avez besoin d’une discussion plus approfondie, n’hésitez pas à communiquer.