3
Seguir
1444
Seguidores

Explicación detallada de la estrategia de negociación de pares de divisas digitales

Creado el: 2024-07-05 16:23:42, Actualizado el: 2024-11-05 17:42:06
comments   3
hits   5807

Explicación detallada de la estrategia de negociación de pares de divisas digitales

Explicación detallada de la estrategia de negociación de pares de divisas digitales

introducción

Recientemente vi el diario cuantitativo de Buu que mencionaba que se pueden usar monedas correlacionadas negativamente para seleccionar monedas y abrir posiciones para obtener ganancias basadas en avances en las diferencias de precios. Las monedas digitales están básicamente correlacionadas positivamente, y solo unas pocas monedas están correlacionadas negativamente. A menudo tienen condiciones de mercado especiales, como las condiciones de mercado independientes de la moneda MEME hace algún tiempo, que no seguían en absoluto la tendencia del mercado. Filtrar Estas monedas se compran y venden en largo después del avance, este método puede generar ganancias bajo ciertas condiciones del mercado. Sin embargo, el método más común en el campo del trading cuantitativo es utilizar la correlación positiva para el trading de pares. En este artículo se presentará brevemente esta estrategia.

El trading de pares de criptomonedas es una estrategia comercial basada en el arbitraje estadístico, que busca obtener ganancias de las desviaciones de precios comprando y vendiendo simultáneamente dos contratos perpetuos de criptomonedas altamente correlacionados. Este artículo presentará los principios de la estrategia, el mecanismo de ganancias, el método de selección de divisas, los riesgos potenciales y las formas de mejorarlo, y proporcionará algunos ejemplos prácticos de código Python.

Principio de estrategia

Las estrategias de trading de pares se basan en la correlación histórica entre los precios de dos criptomonedas. Cuando dos monedas están fuertemente correlacionadas, sus precios se mueven aproximadamente en sincronía. Si en un momento determinado la relación de precios entre ambos se desvía significativamente, se puede considerar que se trata de una anomalía temporal y los precios tenderán a volver a niveles normales. El mercado de divisas digitales está altamente interconectado. Cuando una moneda digital importante (como Bitcoin) experimenta fluctuaciones significativas, generalmente desencadena una reacción en cadena entre otras monedas digitales. Algunas monedas pueden tener una correlación positiva muy obvia, y dicha correlación puede mantenerse porque pertenecen a las mismas instituciones de inversión, a los mismos creadores de mercado y al mismo camino. Algunas monedas están correlacionadas negativamente, pero hay menos monedas correlacionadas negativamente y debido a que todas se ven afectadas por la tendencia general del mercado, a menudo muestran tendencias de mercado consistentes.

Supongamos que la moneda A y la moneda B tienen una alta correlación de precios. En un momento determinado, el valor medio de la relación precio A/B es 1. Si en un momento determinado, la relación de precios A/B se desvía del aumento en más de 0,001, es decir, más de 1,001, entonces puede operar de las siguientes maneras: abrir una posición larga en B y abrir una posición corta en A. . Por el contrario, cuando la relación precio A/B es inferior a 0,999: abra una posición larga en A y una posición corta en B.

La clave de la rentabilidad reside en las ganancias por diferencia de precios cuando los precios se desvían y vuelven a la normalidad. Dado que las desviaciones de precios suelen ser de corta duración, los operadores pueden cerrar sus posiciones cuando los precios vuelven a la media y obtener ganancias de la diferencia.

Preparar los datos

Importar la biblioteca correspondiente

Estos códigos se pueden usar directamente, pero es mejor descargar Anancoda y depurarlo en un Jupyer Notebook. Incluye directamente paquetes para el análisis de datos de uso común.

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

Obtenga todos los pares comerciales que se están negociando

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

Descargar la función de la línea K

La función principal de la función GetKlines es obtener los datos históricos de la línea K del contrato perpetuo del par comercial especificado del intercambio de Binance y almacenar estos datos en un Pandas DataFrame. Los datos de K-line incluyen precio de apertura, precio más alto, precio más bajo, precio de cierre, volumen de operaciones y otra información. Esta vez utilizamos principalmente datos de precios de cierre.

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

Descargar datos

La cantidad de datos es relativamente grande. Para descargar más rápido, solo se obtuvieron los datos horarios de la línea K de los últimos tres meses. df_close contiene datos de precios de cierre para todas las monedas

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

Motor de pruebas retrospectivas

Define un objeto Exchange para la siguiente prueba retrospectiva

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)

Análisis de correlación para filtrar monedas

El cálculo de correlación es un método estadístico que se utiliza para medir la relación lineal entre dos variables. El método de cálculo de correlación más comúnmente utilizado es el coeficiente de correlación de Pearson. A continuación se presentan los principios, fórmulas y métodos de implementación para el cálculo de correlación. El coeficiente de correlación de Pearson se utiliza para medir la relación lineal entre dos variables, y su rango de valores está entre -1 y 1:

  • 1 Indica una correlación positiva perfecta, donde las dos variables siempre cambian sincrónicamente. Cuando una variable aumenta, la otra variable también aumenta proporcionalmente. Cuanto más cerca esté de 1, más fuerte será la correlación.
  • -1 Indica una correlación negativa perfecta, donde las dos variables siempre cambian en direcciones opuestas. Cuanto más cerca esté de -1, más fuerte será la correlación negativa.
  • 0 Indica que no hay correlación lineal, no existe una relación de línea recta entre las dos variables.

El coeficiente de correlación de Pearson determina la correlación entre dos variables calculando su covarianza y desviación estándar. La fórmula es la siguiente:

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

en:

  • ( \rho_{X,Y} ) es una variable( X ) y ( Y ) El coeficiente de correlación de Pearson.
  • ( \text{cov}(X,Y) ) Sí ( X ) y ( Y ) La covarianza de .
  • ( \sigma_X ) y ( \sigma_Y ) Ellos son( X ) y ( Y ) La desviación estándar de .

Por supuesto, no es necesario preocuparse demasiado por cómo se calcula. Puede calcular la correlación de todas las monedas utilizando solo una línea de código Python. La figura muestra un mapa de correlación. El rojo representa una correlación positiva, el azul una correlación negativa y cuanto más oscuro es el color, más fuerte es la correlación. Se puede ver que grandes áreas son de color rojo oscuro, por lo que la correlación positiva de la moneda digital es muy fuerte.

Explicación detallada de la estrategia de negociación de pares de divisas digitales

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

En función de la correlación, se seleccionan los 20 pares de divisas más relevantes. Los resultados son los siguientes: Sus correlaciones son muy fuertes, todas por encima de 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

El código correspondiente es el siguiente:

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)

Verificación mediante backtesting

El código de backtest específico es el siguiente. La estrategia de demostración se centra en observar la relación de precios de dos criptomonedas (IOTA y ZIL) y operar en función de los cambios en esta relación. Los pasos específicos son los siguientes:

  1. inicialización

    • Definir pares comerciales (pair_a = ‘IOTA’, pair_b = ‘ZIL’).
    • Crear un objeto de intercambioe, el saldo inicial es de $10,000 y la tarifa de transacción es del 0,02%.
    • Cálculo de la relación de precio medio inicialavg
    • Establecer un valor de transacción inicialvalue = 1000
  2. Procesar iterativamente los datos de precios

    • Recorrer los datos de precios en cada punto temporaldf_close
    • Calcula la desviación de la relación de precios actual respecto de la media.diff
    • Calcular el valor de la transacción objetivo en función de la desviaciónaim_value, por cada desviación de 0,01, intercambie un valor. Y decidir sobre operaciones de compra y venta en función de las posiciones de cuenta corriente y las condiciones de precios.
    • Si la desviación es demasiado grande, ejecute una venta.pair_a y comprarpair_b funcionar.
    • Si la desviación es demasiado pequeña, ejecute una compra.pair_a y venderpair_b funcionar.
  3. Media ajustada

    • Relación de precio promedio actualizadaavg, con el fin de reflejar la última relación de precios.
  4. Actualización de Cuentas y Registros

    • Actualizar la información de posición y saldo de la cuenta de cambio.
    • Registre el estado de la cuenta en cada paso (activos totales, tenencias, tarifas de transacción, posiciones largas y cortas) parares_list
  5. Salida de resultados

    • Voluntad res_list Convertir a marco de datosres, para su posterior análisis y presentación.
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);

Se realizaron pruebas retrospectivas de un total de 4 grupos de monedas y los resultados fueron relativamente ideales. Los cálculos de correlación actuales utilizan datos futuros, por lo que no son muy precisos. Este artículo también divide los datos en dos partes, basadas en la correlación calculada en el frente y las transacciones probadas retrospectivamente en el reverso. Los resultados fueron un poco desiguales, pero aún así bastante buenos. Corresponde al usuario ejercer la verificación.

Explicación detallada de la estrategia de negociación de pares de divisas digitales

Riesgos potenciales y formas de mejorar

Aunque la estrategia de trading de pares puede ser rentable en teoría, aún existen algunos riesgos en la operación real: la correlación entre las divisas puede cambiar con el tiempo, provocando que la estrategia falle; en condiciones extremas del mercado, las desviaciones de precios pueden aumentar, lo que resulta en grandes pérdidas; La baja liquidez de ciertas monedas puede dificultar la ejecución de transacciones o aumentar los costos; las tarifas generadas por transacciones frecuentes pueden erosionar las ganancias.

Para reducir el riesgo y mejorar la estabilidad de la estrategia, se pueden considerar las siguientes medidas de mejora: recalcular periódicamente la correlación entre las divisas y ajustar los pares comerciales a tiempo; establecer puntos de stop loss y take profit para controlar la pérdida máxima de una sola transacción; Opere con múltiples pares de monedas para diversificar el riesgo.

en conclusión

La estrategia de negociación de pares de divisas digitales logra ganancias aprovechando la correlación entre los precios de las divisas y realizando operaciones de arbitraje cuando los precios se desvían. Esta estrategia tiene una alta viabilidad teórica. Más adelante se publicará un código fuente de estrategia en tiempo real simple basado en esta estrategia. Si tiene más preguntas o necesita más discusión, no dude en comunicarse.