
Kürzlich habe ich Buus quantitatives Tagebuch gesehen, in dem erwähnt wurde, dass man negativ korrelierte Währungen zur Auswahl von Währungen verwenden und Positionen eröffnen kann, um auf der Grundlage von Preisunterschieden Gewinne zu erzielen. Digitale Währungen sind grundsätzlich positiv korreliert, und nur wenige Währungen sind negativ korreliert. Sie haben oft besondere Marktbedingungen, wie beispielsweise die unabhängigen Marktbedingungen der MEME-Münze vor einiger Zeit, die dem Trend des Marktes überhaupt nicht folgten. Herausfiltern und bleiben Sie auch nach dem Durchbruch noch lange auf diesen Währungen, mit dieser Methode können unter bestimmten Marktbedingungen Gewinne erzielt werden. Die gängigste Methode im Bereich des quantitativen Handels ist jedoch die Verwendung einer positiven Korrelation für den Paarhandel. In diesem Artikel wird diese Strategie kurz vorgestellt.
Beim Handel mit Kryptowährungspaaren handelt es sich um eine auf statistischer Arbitrage basierende Handelsstrategie, die darauf abzielt, durch den gleichzeitigen Kauf und Verkauf von zwei zeitlich unbefristeten Kontrakten mit hoher Korrelation zwischen zwei Kryptowährungen Gewinne aus Preisabweichungen zu erzielen. Dieser Artikel stellt die Grundsätze der Strategie, den Gewinnmechanismus, die Methode zur Währungsprüfung, potenzielle Risiken und Verbesserungsmöglichkeiten vor und bietet einige praktische Python-Codebeispiele.
Paarhandelsstrategien basieren auf der historischen Korrelation zwischen den Preisen zweier Kryptowährungen. Wenn zwei Währungen stark korreliert sind, bewegen sich ihre Preise ungefähr synchron. Weicht das Preisverhältnis zwischen den beiden zu einem bestimmten Zeitpunkt erheblich ab, kann davon ausgegangen werden, dass es sich um eine vorübergehende Anomalie handelt und die Preise tendenziell wieder auf ein normales Niveau zurückkehren. Der Markt für digitale Währungen ist stark vernetzt. Wenn eine wichtige digitale Währung (wie Bitcoin) erheblichen Schwankungen unterliegt, löst dies normalerweise eine Kettenreaktion unter anderen digitalen Währungen aus. Einige Währungen weisen möglicherweise eine sehr offensichtliche positive Korrelation auf, und diese Korrelation kann auch anhalten, weil sie zu denselben Investmentinstituten, denselben Market Makern und demselben Kurs gehören. Einige Währungen sind negativ korreliert, es gibt jedoch weniger negativ korrelierte Währungen, und da sie alle vom allgemeinen Markttrend beeinflusst werden, zeigen sie häufig konsistente Markttrends.
Nehmen wir an, dass Münze A und Münze B eine hohe Preiskorrelation aufweisen. Zu einem bestimmten Zeitpunkt beträgt der Durchschnittswert des A/B-Preisverhältnisses 1. Wenn das Preisverhältnis A/B zu einem bestimmten Zeitpunkt um mehr als 0,001, also mehr als 1,001, vom Anstieg abweicht, können Sie auf folgende Weise handeln: Öffnen Sie eine Long-Position auf B und eine Short-Position auf A. . Im Gegenteil, wenn das A/B-Preisverhältnis niedriger als 0,999 ist: Eröffnen Sie eine Long-Position auf A und eine Short-Position auf B.
Der Schlüssel zur Rentabilität liegt in den Preisdifferenzgewinnen, die sich ergeben, wenn die Preise abweichen und sich wieder normalisieren. Da Preisabweichungen in der Regel nur von kurzer Dauer sind, können Händler ihre Positionen schließen, wenn die Preise zum Mittelwert zurückkehren, und von der Differenz profitieren.
Diese Codes können direkt verwendet werden, am besten laden Sie jedoch Anancoda herunter und debuggen es in einem Jupyer-Notebook. Enthält direkt Pakete für häufig verwendete Datenanalysen.
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) # 获取所有的正在交易的交易对
Die Hauptfunktion der GetKlines-Funktion besteht darin, die historischen K-Line-Daten des unbefristeten Vertrags des angegebenen Handelspaares von der Binance-Börse abzurufen und diese Daten in einem Pandas DataFrame zu speichern. Zu den K-Line-Daten zählen Eröffnungskurs, Höchstkurs, Tiefstkurs, Schlusskurs, Handelsvolumen und weitere Informationen. Dieses Mal verwenden wir hauptsächlich Schlusskursdaten.
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
Die Datenmenge ist relativ groß. Um den Download zu beschleunigen, wurden nur die stündlichen K-Line-Daten der letzten drei Monate abgerufen. df_close enthält Schlusskursdaten für alle Währungen
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')
Definiert ein Exchange-Objekt für den folgenden Backtest
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)
Die Korrelationsrechnung ist ein Verfahren der Statistik, mit dem der lineare Zusammenhang zwischen zwei Variablen gemessen wird. Die am häufigsten verwendete Methode zur Korrelationsberechnung ist der Korrelationskoeffizient nach Pearson. Nachfolgend finden Sie die Prinzipien, Formeln und Implementierungsmethoden zur Korrelationsberechnung. Der Korrelationskoeffizient nach Pearson dient zur Messung der linearen Beziehung zwischen zwei Variablen und sein Wertebereich liegt zwischen -1 und 1:
Der Pearson-Korrelationskoeffizient bestimmt die Korrelation zwischen zwei Variablen, indem er ihre Kovarianz und Standardabweichung berechnet. Die Formel lautet wie folgt:
[ \rho_{X,Y} = \frac{\text{cov}(X,Y)}{\sigma_X \sigma_Y} ]
In:
Über die Berechnung müssen Sie sich natürlich keine großen Gedanken machen. Sie können die Korrelation aller Währungen mit nur einer Zeile Python-Code berechnen. Die Abbildung zeigt eine Korrelations-Heatmap. Rot steht für positive Korrelation, Blau für negative Korrelation und je dunkler die Farbe, desto stärker die Korrelation. Es ist ersichtlich, dass große Bereiche dunkelrot sind, was bedeutet, dass die positive Korrelation der digitalen Währung sehr stark ist.

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);
Basierend auf der Korrelation werden die 20 relevantesten Währungspaare ausgewählt. Die Ergebnisse sind wie folgt. Ihre Korrelationen sind sehr stark, alle über 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
Der entsprechende Code lautet wie folgt:
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)
Der spezifische Backtest-Code lautet wie folgt. Die Demo-Strategie konzentriert sich auf die Beobachtung des Preisverhältnisses zweier Kryptowährungen (IOTA und ZIL) und den Handel basierend auf Änderungen dieses Verhältnisses. Die einzelnen Schritte sind wie folgt:
Initialisierung:
e, der Anfangssaldo beträgt 10.000 $ und die Transaktionsgebühr beträgt 0,02 %.avg。value = 1000。Preisdaten iterativ verarbeiten:
df_close。diff。aim_value, für jede Abweichung von 0,01 wird ein Wert gehandelt. Und entscheiden Sie auf Basis der aktuellen Kontopositionen und Preisbedingungen über Kauf- und Verkaufstransaktionen.pair_a und kaufenpair_b arbeiten.pair_a und verkaufenpair_b arbeiten.Angepasster Mittelwert:
avg, um das aktuelle Preisverhältnis widerzuspiegeln.Aktualisieren von Konten und Datensätzen:
res_list。Ergebnisausgabe:
res_list In Datenrahmen konvertierenres, zur weiteren Analyse und Präsentation.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);
Insgesamt wurden vier Währungsgruppen einem Backtesting unterzogen und die Ergebnisse waren relativ optimal. Die aktuellen Korrelationsberechnungen basieren auf zukünftigen Daten und sind daher nicht sehr präzise. Auch dieser Artikel unterteilt die Daten in zwei Teile, basierend auf der berechneten Korrelation im Vordergrund und den Backtesting-Transaktionen im Hintergrund. Die Ergebnisse waren etwas abweichend, aber immer noch ziemlich gut. Die Durchführung der Überprüfung bleibt dem Benutzer überlassen.

Obwohl die Paarhandelsstrategie theoretisch profitabel sein kann, gibt es im tatsächlichen Betrieb immer noch einige Risiken: Die Korrelation zwischen den Währungen kann sich im Laufe der Zeit ändern, was zum Scheitern der Strategie führt. Unter extremen Marktbedingungen können die Preisabweichungen zunehmen, was zu großen Verlusten führt. Die geringe Liquidität bestimmter Währungen kann die Ausführung von Transaktionen erschweren oder die Kosten erhöhen; die durch häufige Transaktionen entstehenden Gebühren können die Gewinne schmälern.
Um das Risiko zu verringern und die Stabilität der Strategie zu verbessern, können die folgenden Verbesserungsmaßnahmen in Betracht gezogen werden: regelmäßige Neuberechnung der Korrelation zwischen Währungen und rechtzeitige Anpassung der Handelspaare; Festlegung von Stop-Loss- und Take-Profit-Punkten, um den maximalen Verlust einer einzelnen Transaktion zu kontrollieren; Handeln Sie mit mehreren Münzpaaren, um das Risiko zu streuen.
Mit der Handelsstrategie für digitale Währungspaare werden Gewinne erzielt, indem die Korrelation zwischen Währungskursen ausgenutzt und bei abweichenden Kursen Arbitragegeschäfte durchgeführt werden. Diese Strategie hat eine hohe theoretische Machbarkeit. Ein einfacher Echtzeitstrategie-Quellcode basierend auf dieser Strategie wird später veröffentlicht. Wenn Sie weitere Fragen haben oder Bedarf für eine weitere Diskussion haben, können Sie sich gerne an uns wenden.