Die Ressourcen sind geladen. Beförderung...

Ausführliche Erläuterung der Strategie für den Handel mit digitalen Währungspaaren

Schriftsteller:FMZ~Lydia, Erstellt: 2024-07-08 11:41:23, aktualisiert: 2024-07-12 15:54:35

img

Einleitung

Vor kurzem sah ich das Quantitative Diary von BuOu, in dem erwähnt wurde, dass man negativ korrelierte Währungen verwenden kann, um Währungen auszuwählen und Positionen zu eröffnen, um Gewinne zu erzielen, die auf Preisdifferenzdurchbrüchen basieren. Digitale Währungen sind grundsätzlich positiv korreliert, und nur wenige Währungen sind negativ korreliert, oft mit speziellen Marktbedingungen, wie z. B. den unabhängigen Marktbedingungen von MEME-Münzen, die sich völlig vom Markttrend unterscheiden. Diese Währungen können ausgewählt werden und lange nach dem Durchbruch weitergehen. Diese Methode kann unter bestimmten Marktbedingungen Gewinne erzielen. Die häufigste Methode im Bereich des quantitativen Handels ist jedoch die Verwendung von positiver Korrelation für den Paarhandel. Dieser Artikel wird diese Strategie kurz vorstellen.

Der digitale Währungspaarhandel ist eine Handelsstrategie, die auf statistischer Arbitrage basiert, bei der gleichzeitig zwei stark korrelierte Kryptowährungen gekauft und verkauft werden, um Gewinne aus Preisabweichungen zu erzielen.

Strategieprinzip

Die Pair-Trading-Strategien beruhen auf der historischen Korrelation zwischen den Preisen zweier digitaler Währungen. Wenn die Preise zweier Währungen eine starke Korrelation aufweisen, sind ihre Preistrends im Allgemeinen synchronisiert. Wenn sich das Preisverhältnis zwischen den beiden zu einem bestimmten Zeitpunkt erheblich abweist, kann dies als vorübergehende Anomalie angesehen werden und der Preis wird dazu neigen, auf normale Niveaus zurückzukehren. Der digitale Währungsmarkt ist stark miteinander verbunden. Wenn eine große digitale Währung (wie Bitcoin) erheblich schwankt, löst sie in der Regel eine koordinierte Reaktion in anderen digitalen Währungen aus. Einige Währungen können eine sehr offensichtliche positive Korrelation haben, die aufgrund der gleichen Investitionsinstitutionen, der gleichen Marktmacher und der gleichen Spur andauern kann. Einige Währungen sind negativ korreliert, aber es gibt weniger negativ korrelierte Währungen, und da sie alle vom Markttrend beeinflusst werden, haben sie oft konsistente Markttrends.

Nehmen wir an, dass Währung A und Währung B eine hohe Preiskorrelation aufweisen. Zu einem bestimmten Zeitpunkt beträgt der Durchschnittswert des A/B-Preisverhältnisses 1. Wenn sich das A/B-Preisverhältnis zu einem bestimmten Zeitpunkt um mehr als 0,001, d. h. mehr als 1,001, abweist, dann können Sie auf folgende Weise handeln: Öffnen Sie eine Long-Position bei B und eine Short-Position bei A. Im Gegenteil, wenn das A/B-Preisverhältnis unter 0,999 liegt: Öffnen Sie eine Long-Position bei A und öffnen Sie eine Short-Position bei B.

Der Schlüssel zur Rentabilität liegt in den Spread-Gewinnen, wenn die Preise vom Durchschnitt abweichen und wieder normal werden.

Bereiten Sie die Daten vor

Importieren der entsprechenden Bibliothek

Diese Codes können direkt verwendet werden. Am besten ist es, Anancoda herunterzuladen und in Jupyer Notebook zu debuggen. Es enthält Pakete für die häufig verwendete Datenanalyse direkt.

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

Alle Handelspare werden gehandelt.

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) # Get all trading pairs being traded

Funktion K-Line herunterladen

Die Hauptfunktion der GetKlines-Funktion besteht darin, die historischen K-Line-Daten des angegebenen Handelspaar-Perpetual-Kontrakts von der Binance-Börse zu erhalten und die Daten in einem Pandas DataFrame zu speichern. Die K-Line-Daten enthalten Informationen wie Eröffnungspreis, höchster Preis, niedrigster Preis, Schlusskurs und Handelsvolumen. Diesmal verwenden wir hauptsächlich die 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

Daten herunterladen

Das Datenvolumen ist relativ groß. Um schneller herunterzuladen, werden nur die stündlichen K-Line-Daten der letzten drei Monate erhalten. df_close enthält die Schlusskursdaten aller 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')

Backtesting-Engine

Wir definieren ein Austauschobjekt für den folgenden Backtest.

class Exchange:
    def __init__(self, trade_symbols, fee=0.0002, initial_balance=10000):
        self.initial_balance = initial_balance #Initial assets
        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 #Deduction fee
        self.account['USDT']['fee'] += price*amount*self.fee
        self.account[symbol]['fee'] += price*amount*self.fee
        if cover_amount > 0: #Close the position first
            self.account['USDT']['realised_profit'] += -direction*(price - self.account[symbol]['hold_price'])*cover_amount  #profit
            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): #Update the assets
        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)

Korrelationsanalyse mit Filterwährungen

Die Korrelationsberechnung ist eine Methode in der Statistik, die zur Messung der linearen Beziehung zwischen zwei Variablen verwendet wird. Die am häufigsten verwendete Korrelationsberechnungsmethode ist der Pearson-Korrelationskoeffizient. Folgendes ist das Prinzip, die Formel und die Implementierungsmethode der Korrelationsberechnung. Der Pearson-Korrelationskoeffizient wird verwendet, um die lineare Beziehung zwischen zwei Variablen zu messen, und sein Wertebereich liegt zwischen -1 und 1:

  • 1 zeigt eine perfekte positive Korrelation an, bei der sich die beiden Variablen immer synchron ändern. Wenn eine Variable steigt, steigt auch die andere proportional. Je näher sie an 1 ist, desto stärker ist die Korrelation.
  • -1 zeigt eine perfekte negative Korrelation an, bei der sich die beiden Variablen immer in entgegengesetzte Richtungen ändern.
  • 0 bedeutet keine lineare Korrelation, es gibt keine gerade Beziehung zwischen den beiden Variablen.

Der Pearson-Korrelationskoeffizient bestimmt die Korrelation zwischen zwei Variablen durch Berechnung ihrer Kovarianz und Standardabweichung.

img

in denen:

  • imgist der Pearson-Korrelationskoeffizient zwischen den Variablen X und Y.
  • imgist die Kovarianz von X und Y.
  • imgundimgsind die Standardabweichungen von X bzw. Y.

Natürlich müssen Sie sich nicht zu sehr darum kümmern, wie es berechnet wird. Sie können 1 Zeile Code in Python verwenden, um die Korrelation aller Währungen zu berechnen. Die Abbildung zeigt eine Korrelationswärmekarte. Rot repräsentiert positive Korrelation, Blau repräsentiert negative Korrelation, und je dunkler die Farbe, desto stärker die Korrelation. Sie können sehen, dass der größte Teil des Bereichs dunkelrot ist, so dass die positive Korrelation digitaler Währungen sehr stark ist.

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

Auf der Grundlage der Korrelation werden die 20 am häufigsten korrelierten Währungspaare ausgewählt.

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:

corr_pairs = corr.unstack()

# Remove self-correlation (i.e. values ​​on the diagonal)
corr_pairs = corr_pairs[corr_pairs != 1]

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

# Extract the top 20 most and least correlated currency pairs
most_correlated = sorted_corr_pairs.tail(40)[::-2]

print("The top 20 most correlated currency pairs are:")
print(most_correlated)

Zurückprüfungsprüfung

Der spezifische Backtest-Code ist wie folgt. Die Demonstrationsstrategie beobachtet hauptsächlich das Preisverhältnis von zwei Kryptowährungen (IOTA und ZIL) und handelt entsprechend den Änderungen dieses Verhältnisses. Die spezifischen Schritte sind wie folgt:

  1. Initialisierung:
  • Definition von Handelsparen (Pair_a = IOTA, Paar_b = ZIL).
  • Erstellen eines Austauschobjektsemit einem Anfangsguthaben von $10.000 und einer Transaktionsgebühr von 0.02%.
  • Berechnung der anfänglichen durchschnittlichen Preisquoteavg.
  • Festlegen eines ursprünglichen Transaktionswertsvalue = 1000.
  1. Iteration über die Preisdaten:
  • Durchqueren der Preisdaten zu jedem Zeitpunktdf_close.
  • Berechnet die Abweichung des aktuellen Preisverhältnisses vom Mittelwertdiff.
  • Der Zieltransaktionswert wird auf der Grundlage der Abweichung berechnetaim_valueDie Kauf- und Verkaufsaktionen werden anhand der Leistungsbilanz und der Preislage bestimmt.
  • Wenn die Abweichung zu groß ist, verkaufenpair_aund kaufenpair_b operations.
  • Wenn die Abweichung zu klein ist, kaufenpair_aund verkaufenpair_bdie Operationen durchgeführt werden.
  1. Das Mittel anpassen:
  • Aktualisiert das durchschnittliche Preisverhältnisavgdie neuesten Preisquoten widerspiegeln.
  1. Aktualisierung von Konten und Aufzeichnungen:
  • Aktualisierung der Positions- und Saldoinformationen des Umtauschkontos.
  • Der Kontozustand wird in jedem Schritt (Gesamtvermögen, gehaltene Vermögenswerte, Transaktionsgebühren, lange und kurze Positionen) aufgezeichnet, umres_list.
  1. Ergebnis:
  • Umwandelnres_listauf Datensatzreszur weiteren Analyse und Darstellung.
pair_a = 'IOTA'
pair_b = "ZIL"
e = Exchange([pair_a,pair_b], fee=0.0002, initial_balance=10000) #Exchange definition is placed in the comments section
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);

Die aktuelle Korrelationsberechnung verwendet zukünftige Daten, so dass sie nicht sehr genau ist. Dieser Artikel teilt die Daten auch in zwei Teile, basierend auf der vorherigen Berechnung der Korrelation und dem anschließenden Backtest-Handel. Die Ergebnisse sind ein wenig anders, aber nicht schlecht. Wir überlassen es dem Benutzer zu üben und zu überprüfen.

img

Potenzielle Risiken und Verbesserungsmöglichkeiten

Obwohl die Handelsstrategie des Paares theoretisch profitabel sein kann, bestehen im tatsächlichen Betrieb immer noch einige Risiken: Die Korrelation zwischen Währungen kann sich im Laufe der Zeit ändern, was dazu führt, dass die Strategie fehlschlägt; unter extremen Marktbedingungen können Preisabweichungen zunehmen, was zu größeren Verlusten führt; die geringe Liquidität bestimmter Währungen kann die Durchführung von Transaktionen erschweren oder die Kosten erhöhen; und die Gebühren, die durch häufige Transaktionen entstehen, können den Gewinn beeinträchtigen.

Um Risiken zu reduzieren und die Stabilität der Strategien zu verbessern, können folgende Verbesserungsmaßnahmen in Betracht gezogen werden: Regelmäßige Neuberechnung der Korrelation zwischen Währungen und rechtzeitige Anpassung der Handelspare; Festlegung von Stop-Loss- und Take-Profit-Punkten, um den maximalen Verlust eines einzelnen Geschäfts zu kontrollieren; Handel mit mehreren Währungspaaren gleichzeitig zur Diversifizierung der Risiken.

Schlussfolgerung

Die digitale Währungspaar-Handelsstrategie erzielt Gewinne, indem sie die Korrelation der Währungspreise nutzt und Arbitrageoperationen durchführt, wenn die Preise abweichen. Diese Strategie hat eine hohe theoretische Machbarkeit. Ein einfacher Live-Handelsstrategie-Quellcode basierend auf dieser Strategie wird später veröffentlicht. Wenn Sie weitere Fragen haben oder eine weitere Diskussion benötigen, können Sie sich gerne melden.


Mehr