Las transacciones de pareja basadas en tecnología impulsada por datos

El autor:La bondad, Creado: 2019-08-21 13:50:23, Actualizado: 2023-10-19 21:01:31

img

El emparejamiento de operaciones es un buen ejemplo de cómo desarrollar estrategias de operaciones basadas en el análisis matemático. En este artículo, vamos a demostrar cómo utilizar datos para crear y automatizar estrategias de operaciones de emparejamiento.

Principios básicos

假设你有一对投资标的X和Y具有一些潜在的关联,例如两家公司生产相同的产品,如百事可乐和可口可乐。你希望这两者的价格比率或基差(也称为差价)随时间的变化而保持不变。然而,由于临时供需变化,如一个投资标的的大买/卖订单,对其中一家公司的重要新闻的反应等,这两对之间的价差可能会不时出现分歧。在这种情况下,一只投资标的向上移动而另一只投资标的相对于彼此向下移动。如果你希望这种分歧随着时间的推移恢复正常,你就可以发现交易机会(或套利机会)。此种套利机会在数字货币市场或者国内商品期货市场比比皆是,比如BTC与避险资产的关系;期货中豆粕,豆油与大豆品种之间的关系.

Cuando hay una diferencia temporal de precios, el comercio venderá el indicador de excelente desempeño y comprará el indicador de mal desempeño. Puedes estar seguro de que la diferencia de interés entre los dos indicadores terminará por la caída del indicador de excelente desempeño o la recuperación del indicador de mal desempeño o ambos. Tu comercio ganará dinero en todos estos escenarios similares.

Por lo tanto, el comercio de pareja es una estrategia de negociación neutra en el mercado que permite a los operadores beneficiarse de casi cualquier condición del mercado: tendencia alcista, tendencia bajista o ajuste horizontal.

La definición del concepto: dos supuestos indicadores de inversión

  • Construimos nuestro entorno de investigación en la plataforma de cuantificación de inventores

En primer lugar, para que el trabajo se desarrolle sin problemas, necesitamos construir nuestro entorno de investigación, y en este artículo usamos la plataforma de cuantificación de los inventores.FMZ.COMEl proyecto de Docker fue desarrollado en el año 2010 para desarrollar un entorno de investigación basado en el uso de una API rápida y cómoda y un sistema de Docker completo.

En el nombre oficial de la plataforma de cuantificación de los inventores, este sistema Docker se conoce como sistema administrador.

Para más información sobre cómo implementar administradores y robots, consulte mi artículo anterior:https://www.fmz.com/bbs-topic/4140

Los lectores que quieran comprar su propio administrador de servidores en la nube pueden consultar este artículo:https://www.fmz.com/bbs-topic/2848

Después de haber implementado con éxito un buen sistema de servidores y administradores en la nube, ahora vamos a instalar el mayor templo de Python: Anaconda.

Para implementar todos los entornos de programación relacionados que se requieren en este artículo (la librería de dependencias, la administración de versiones, etc.), el método más sencillo es usar Anaconda. Es un ecosistema de ciencias de datos Python y un administrador de librería de dependencias.

Para más información sobre cómo instalar Anaconda, consulte el manual oficial de Anaconda:https://www.anaconda.com/distribution/

本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.

Estos trabajos básicos también pueden ser consultados en mi artículo anterior sobre cómo configurar el entorno de Anaconda y las bibliotecas numpy y pandas.https://www.fmz.com/digest-topic/4169

A continuación, vamos a implementar en el código una "tipo de inversión de dos hipótesis".

import numpy as np
import pandas as pd

import statsmodels
from statsmodels.tsa.stattools import coint
# just set the seed for the random number generator
np.random.seed(107)

import matplotlib.pyplot as plt

Sí, también vamos a usar la matplotlib, la biblioteca de gráficos muy famosa en Python.

Vamos a generar X de un indicador de inversión hipotético y simular su retorno diario mediante una distribución normal.

# Generate daily returns
Xreturns = np.random.normal(0, 1, 100) 
# sum them and shift all the prices up
X = pd.Series(np.cumsum(
    Xreturns), name='X') 
    + 50
X.plot(figsize=(15,7))
plt.show()

img

X de la indicación de la inversión, para simular su rendimiento diario mediante una distribución normal

Ahora bien, Y y X que generamos tienen una fuerte correlación entre sí, por lo que el precio de Y debe ser muy similar a la variación de X. Modelado por tomar X, moverlo hacia arriba y añadir algo de ruido aleatorio extraído de la distribución normal.

noise = np.random.normal(0, 1, 100)
Y = X + 5 + noise
Y.name = 'Y'
pd.concat([X, Y], axis=1).plot(figsize=(15,7))
plt.show()

img

X y Y de la indicación de inversión

La integración

协整非常类似于相关性,意味着两个数据系列之间的比率将在平均值附近变化.Y和X这两个系列遵循以下内容:

Y = X + e

En este caso, el r es la proporción constante y e es el ruido.

Para los pares de transacciones entre dos secuencias de tiempo, esta proporción debe coincidir con los valores esperados en el tiempo, es decir, deben ser conjugados. La secuencia de tiempo que construimos arriba es conjugada. Ahora vamos a trazar la proporción entre ambos para que podamos ver cómo se ve.

(Y/X).plot(figsize=(15,7)) 
plt.axhline((Y/X).mean(), color='red', linestyle='--') 
plt.xlabel('Time')
plt.legend(['Price Ratio', 'Mean'])
plt.show()

img

Ratio y promedio entre los precios de dos indicadores de inversión co-integrados

Pruebas de integración

Hay una manera fácil de probar esto, usando statsmodels.tsa.stattools. Deberíamos ver un valor de p muy bajo porque hemos creado artificialmente dos series de datos que se integran lo más posible.

# compute the p-value of the cointegration test
# will inform us as to whether the ratio between the 2 timeseries is stationary
# around its mean
score, pvalue, _ = coint(X,Y)
print pvalue

El resultado fue: 1.81864477307e-17

Nota: Relatividad y coherencia

Relacionados y conjugados, aunque son similares en teoría, no son lo mismo. Veamos ejemplos de series de datos relacionadas pero no conjugadas, y viceversa. Primero examinemos la relación de las series que acabamos de generar.

X.corr(Y)

El resultado es: 0.951.

Como era de esperar, esto es muy alto. Pero ¿qué pasa con dos series relacionadas pero no coherentes? Un ejemplo simple es dos series de datos con desviaciones.

ret1 = np.random.normal(1, 1, 100)
ret2 = np.random.normal(2, 1, 100)

s1 = pd.Series( np.cumsum(ret1), name='X')
s2 = pd.Series( np.cumsum(ret2), name='Y')

pd.concat([s1, s2], axis=1 ).plot(figsize=(15,7))
plt.show()
print 'Correlation: ' + str(X_diverging.corr(Y_diverging))
score, pvalue, _ = coint(X_diverging,Y_diverging)
print 'Cointegration test p-value: ' + str(pvalue)

img

Dos series relacionadas (no integradas)

Coeficientes relacionados: 0.998 P-valor de la prueba de integración: 0.258

Los ejemplos sencillos de co-integración sin correlación son las secuencias de distribución normal y las ondas cuadradas.

Y2 = pd.Series(np.random.normal(0, 1, 800), name='Y2') + 20
Y3 = Y2.copy()
Y3[0:100] = 30
Y3[100:200] = 10
Y3[200:300] = 30
Y3[300:400] = 10
Y3[400:500] = 30
Y3[500:600] = 10
Y3[600:700] = 30
Y3[700:800] = 10
Y2.plot(figsize=(15,7))
Y3.plot()
plt.ylim([0, 40])
plt.show()
# correlation is nearly zero
print 'Correlation: ' + str(Y2.corr(Y3))
score, pvalue, _ = coint(Y2,Y3)
print 'Cointegration test p-value: ' + str(pvalue)

img

La relevancia: 0.007546 P-valor del ensayo de integración: 0.0

¡La correlación es muy baja, pero el p-valor muestra una perfecta coherencia!

¿Cómo se hace un trato de pareja?

Debido a que dos secuencias de tiempo coordinadas (por ejemplo, X y Y) están alineadas y desviadas entre sí, a veces se producen diferencias altas y bajas de margen. Hacemos una operación de emparejamiento comprando un indicador y vendiendo otro. Así, si los dos indicadores caen o suben juntos, no ganamos ni perdemos dinero, es decir, somos neutrales en el mercado.

Volviendo a Y = X + e y X y Y en la parte superior, haciendo que la relación ((Y / X) se mueva alrededor de su valor medio, ganamos dinero con la relación de retorno de valor medio. Para hacer esto, observamos cuando X y Y están muy alejados, es decir, cuando el umbral es demasiado alto o demasiado bajo:

  • Hacer más de una proporción: esto es cuando la proporción es muy pequeña y esperamos que aumente. En el ejemplo anterior, abrimos una posición haciendo más de Y y haciendo un espacio X.

  • Ratio de vacío: Es cuando la tasa de vacío es grande y esperamos que cambie por horas. En el ejemplo anterior, abrimos la posición haciendo vacío Y y haciendo más X.

Tenga en cuenta que siempre tenemos una posición arriesgada: si el precio de compra del indicador de negociación pierde valor, la posición arriesgada gana dinero, y viceversa, por lo que somos inmunes a los movimientos del mercado en general.

Si los indicadores X y Y se mueven en relación entre sí, ganaremos o perderemos.

Usar datos para buscar acciones similares a las de los indicadores de transacción

La mejor manera de hacerlo es comenzar con el indicador de transacción que sospechas que puede ser un acuerdo y realizar una prueba estadística.Desviación múltiple de comparaciónEl gobierno de los Estados Unidos está tratando de eliminar la violencia.

Desviación múltiple de comparaciónSe refiere a una situación en la que aumenta la oportunidad de generar erroneamente p-valores importantes al ejecutar muchas pruebas, ya que necesitamos ejecutar muchas pruebas. Si se realizan 100 pruebas con datos aleatorios, deberíamos ver 5 p-valores inferiores a 0.05. Si se comparan n indicadores de transacciones para realizar una combinación completa, se realizarán n-n-1/2.Desviación múltiple de comparación

Por lo tanto, vamos a tratar de encontrar algunos indicadores que muestren una coordinación. Tomemos como ejemplo una canasta de grandes acciones de tecnología estadounidenses en el S&P 500, que operan en segmentos de mercado similares y tienen un precio coordinado.

Se devuelve la matriz de comprobación de integración de la fracción, la matriz de valor p y todos los pares con valor p menor que 0.05.Este método es propenso a tener múltiples desviaciones de comparación, por lo que en realidad necesitan una segunda verificación.En este artículo, para facilitar nuestra explicación, en los ejemplos elegimos ignorar esto.

def find_cointegrated_pairs(data):
    n = data.shape[1]
    score_matrix = np.zeros((n, n))
    pvalue_matrix = np.ones((n, n))
    keys = data.keys()
    pairs = []
    for i in range(n):
        for j in range(i+1, n):
            S1 = data[keys[i]]
            S2 = data[keys[j]]
            result = coint(S1, S2)
            score = result[0]
            pvalue = result[1]
            score_matrix[i, j] = score
            pvalue_matrix[i, j] = pvalue
            if pvalue < 0.02:
                pairs.append((keys[i], keys[j]))
    return score_matrix, pvalue_matrix, pairs

NOTA: Incluimos en los datos el SPX - el mercado impulsa el movimiento de muchos indicadores, y normalmente puedes encontrar dos indicadores que parecen coexistir; pero en realidad no coexisten entre sí, sino con el mercado. Esto se conoce como variables de mezcla. Es importante examinar la participación del mercado en cualquier relación que encuentres.

from backtester.dataSource.yahoo_data_source import YahooStockDataSource
from datetime import datetime
startDateStr = '2007/12/01'
endDateStr = '2017/12/01'
cachedFolderName = 'yahooData/'
dataSetId = 'testPairsTrading'
instrumentIds = ['SPY','AAPL','ADBE','SYMC','EBAY','MSFT','QCOM',
                 'HPQ','JNPR','AMD','IBM']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
                            dataSetId=dataSetId,
                            instrumentIds=instrumentIds,
                            startDateStr=startDateStr,
                            endDateStr=endDateStr,
                            event='history')
data = ds.getBookDataByFeature()['Adj Close']
data.head(3)

img

Ahora vamos a tratar de encontrar una pareja de transacciones que coexistan usando nuestro método.

# Heatmap to show the p-values of the cointegration test
# between each pair of stocks
scores, pvalues, pairs = find_cointegrated_pairs(data)
import seaborn
m = [0,0.2,0.4,0.6,0.8,1]
seaborn.heatmap(pvalues, xticklabels=instrumentIds, 
                yticklabels=instrumentIds, cmap=’RdYlGn_r’, 
                mask = (pvalues >= 0.98))
plt.show()
print pairs
[('ADBE', 'MSFT')]

img

Parece que el aluminio ADBE y el aluminio MSFT funcionan juntos. Veamos el precio para asegurarnos de que realmente tiene sentido.

S1 = data['ADBE']
S2 = data['MSFT']
score, pvalue, _ = coint(S1, S2)
print(pvalue)
ratios = S1 / S2
ratios.plot()
plt.axhline(ratios.mean())
plt.legend([' Ratio'])
plt.show()

img

Gráfico de la relación de precios entre MSFT y ADBE de 2008 a 2017

Esta proporción sí parece una media estable. Las proporciones absolutas no son muy útiles estadísticamente. Es más útil estandarizar nuestra señal al considerarla como una puntuación z. La puntuación z se define como:

Puntuación Z (valor) = (valor media) / Desviación estándar

Advertencias

En realidad, normalmente intentamos hacer algunas extensiones a los datos, siempre que sean distribuidos de forma normal. Sin embargo, muchos datos financieros no son distribuidos de forma normal, por lo que debemos tener mucho cuidado de no simplemente asumir la normalidad o cualquier distribución específica al generar estadísticas. Las distribuciones verdaderas de las proporciones pueden tener un efecto de fatigue, y los datos que tienden a extremos pueden confundir nuestros modelos y causar enormes pérdidas.

def zscore(series):
    return (series - series.mean()) / np.std(series)
zscore(ratios).plot()
plt.axhline(zscore(ratios).mean())
plt.axhline(1.0, color=’red’)
plt.axhline(-1.0, color=’green’)
plt.show()

img

Relación de precios Z entre MSFT y ADBE entre 2008 y 2017

Ahora es más fácil observar que las proporciones se mueven cerca de la media, pero a veces es fácil tener grandes diferencias con la media, y podemos aprovechar esto.

Ahora que hemos discutido los fundamentos de las estrategias de negociación de emparejamiento y hemos determinado indicadores de negociación que se han integrado en conjunto en función de los precios históricos, intentemos desarrollar una señal de negociación.

  • Recolectar datos confiables y limpiarlos

  • Creación de funciones a partir de datos para identificar señales/lógica de transacción

  • Las funciones pueden ser promedios móviles o datos de precios, correlaciones o proporciones de señales más complejas - combine estas para crear nuevas funciones

  • Utiliza estas funciones para generar señales de negociación, es decir, qué señales son compras, ventas o posiciones en blanco.

Afortunadamente, tenemos una plataforma de cuantificación de inventores.fmz.comEl trabajo realizado para nosotros en los cuatro aspectos anteriores es una gran bendición para los desarrolladores de estrategias, que pueden invertir su energía y tiempo en el diseño de la lógica estratégica y en la expansión de las funciones.

En las plataformas de inventores de cuantificación, hay interfaces de todo tipo de intercambios convencionales envasadas, todo lo que tenemos que hacer es llamar a estas interfaces de API, y el resto de la implementación lógica de la base, que ya tiene un equipo de profesionales que lo perfeccionan.

En este artículo, para la integración de la lógica y la explicación de los principios, vamos a hacer una representación de la lógica de base, pero en la práctica, los lectores pueden llamar directamente a las interfaces API cuantificadas por los inventores para hacer los cuatro aspectos anteriores.

¿Qué es lo que está sucediendo?

Paso 1: Establezca su problema

Aquí, tratamos de crear una señal que nos diga si la proporción está comprando o vendiendo en el momento siguiente, es decir, nuestra variable de pronóstico Y:

Y = Ratio es compra (1) o venta (-1)

Y (t) = Signo (t+1) Proporción (t)

Tenga en cuenta que no necesitamos predecir el precio de la indicación de negociación real, ni siquiera necesitamos predecir el valor real de la proporción (aunque podemos), solo necesitamos predecir la dirección de la siguiente proporción.

El segundo paso: recopilar datos fiables y precisos

El inventor de la cuantificación es su amigo! Basta con especificar el indicador que se quiere negociar y la fuente de datos que se quiere utilizar, y extraerá los datos necesarios y los limpiará para dividir los dividendos y los indicadores. Así que tenemos los datos aquí limpios.

En los últimos 10 años (aproximadamente 2500 puntos de datos) hemos obtenido los siguientes datos de los días de negociación utilizando las finanzas de Yahoo: precio de apertura, precio de cierre, precio más alto, precio más bajo y volumen de negociación

Paso 3: Desglosar los datos

No olvides este paso muy importante para probar la precisión del modelo. Estamos usando el siguiente dato para entrenar/verificar/despartir las pruebas.

  • Formación 7 años ~ 70%

  • Prueba ~ 3 años 30%

ratios = data['ADBE'] / data['MSFT']
print(len(ratios))
train = ratios[:1762]
test = ratios[1762:]

Idealmente, también deberíamos hacer conjuntos de verificación, pero no lo haremos por ahora.

Paso 4: Diseño de características

¿Cuál puede ser la función relacionada? Queremos predecir la dirección de los cambios de la proporción. Ya hemos visto que nuestros dos indicadores de transacción son conjugados, por lo que la proporción a menudo se traslada y regresa a la media. Parece que nuestra característica debería ser cierta medida de la media de la proporción, y la diferencia entre el valor actual y el valor medio puede generar nuestra señal de transacción.

En la página web de Facebook, el usuario puede encontrar información sobre el proyecto.

  • 60 días de media móvil: medición de la media móvil

  • Ratio de media móvil de 5 días: medición del valor actual de la media

  • 60 días de diferencia estándar

  • La puntuación z: ((5d MA - 60d MA) / 60d SD

ratios_mavg5 = train.rolling(window=5,
                               center=False).mean()
ratios_mavg60 = train.rolling(window=60,
                               center=False).mean()
std_60 = train.rolling(window=60,
                        center=False).std()
zscore_60_5 = (ratios_mavg5 - ratios_mavg60)/std_60
plt.figure(figsize=(15,7))
plt.plot(train.index, train.values)
plt.plot(ratios_mavg5.index, ratios_mavg5.values)
plt.plot(ratios_mavg60.index, ratios_mavg60.values)
plt.legend(['Ratio','5d Ratio MA', '60d Ratio MA'])
plt.ylabel('Ratio')
plt.show()

img

La relación de precios de 60d y 5d MA

plt.figure(figsize=(15,7))
zscore_60_5.plot()
plt.axhline(0, color='black')
plt.axhline(1.0, color='red', linestyle='--')
plt.axhline(-1.0, color='green', linestyle='--')
plt.legend(['Rolling Ratio z-Score', 'Mean', '+1', '-1'])
plt.show()

img

Proporción de precios de los puntos Z 60-5

¡La puntuación Z de la media de rotación realmente trae consigo la naturaleza de la regresión de la media de la proporción!

Paso 5: Selección del modelo

Comencemos con un modelo muy simple. Veamos el gráfico de la puntuación z y podemos ver que siempre que la puntuación z es demasiado alta o demasiado baja, regresa. Usemos +1/-1 como nuestro umbral para definir demasiado alto y demasiado bajo, y luego podemos usar el siguiente modelo para generar señales de negociación:

  • Cuando z es inferior a -1.0, la proporción es comprar ((1) porque esperamos que z regrese a 0, por lo que la proporción aumenta.

  • Cuando z es superior a 1.0, la proporción es de venta (−1) porque esperamos que z regrese a 0, por lo que la proporción disminuye.

Paso 6: entrenar, verificar y optimizar

Y finalmente, vamos a ver el efecto real de nuestro modelo en los datos reales.

# Plot the ratios and buy and sell signals from z score
plt.figure(figsize=(15,7))
train[60:].plot()
buy = train.copy()
sell = train.copy()
buy[zscore_60_5>-1] = 0
sell[zscore_60_5<1] = 0
buy[60:].plot(color=’g’, linestyle=’None’, marker=’^’)
sell[60:].plot(color=’r’, linestyle=’None’, marker=’^’)
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,ratios.min(),ratios.max()))
plt.legend([‘Ratio’, ‘Buy Signal’, ‘Sell Signal’])
plt.show()

img

Signales de precio de compra y venta

Esta señal parece razonable, parece que vendemos la proporción (punto rojo) cuando es alta o aumenta y compramos de nuevo cuando es baja (punto verde) y disminuye. ¿Qué significa esto para el indicador de negociación real que estamos negociando?

# Plot the prices and buy and sell signals from z score
plt.figure(figsize=(18,9))
S1 = data['ADBE'].iloc[:1762]
S2 = data['MSFT'].iloc[:1762]
S1[60:].plot(color='b')
S2[60:].plot(color='c')
buyR = 0*S1.copy()
sellR = 0*S1.copy()
# When buying the ratio, buy S1 and sell S2
buyR[buy!=0] = S1[buy!=0]
sellR[buy!=0] = S2[buy!=0]
# When selling the ratio, sell S1 and buy S2 
buyR[sell!=0] = S2[sell!=0]
sellR[sell!=0] = S1[sell!=0]
buyR[60:].plot(color='g', linestyle='None', marker='^')
sellR[60:].plot(color='r', linestyle='None', marker='^')
x1,x2,y1,y2 = plt.axis()
plt.axis((x1,x2,min(S1.min(),S2.min()),max(S1.max(),S2.max())))
plt.legend(['ADBE','MSFT', 'Buy Signal', 'Sell Signal'])
plt.show()

img

Señales para comprar y vender acciones de MSFT y ADBE

Observe cómo a veces ganamos dinero con "piernas cortas", a veces ganamos dinero con "piernas largas" y a veces ambas cosas.

Estamos satisfechos con las señales de los datos de entrenamiento. Veamos qué tipo de ganancias puede generar esta señal. Cuando la proporción es baja, podemos hacer un simple retweeter, comprar una proporción (comprar 1 acción ADBE y vender la proporción x acciones MSFT), vender una proporción cuando es alta (comprar 1 acción ADBE y comprar la proporción x acciones MSFT) y calcular las transacciones PnL de estas proporciones.

# Trade using a simple strategy
def trade(S1, S2, window1, window2):
    
    # If window length is 0, algorithm doesn't make sense, so exit
    if (window1 == 0) or (window2 == 0):
        return 0
    
    # Compute rolling mean and rolling standard deviation
    ratios = S1/S2
    ma1 = ratios.rolling(window=window1,
                               center=False).mean()
    ma2 = ratios.rolling(window=window2,
                               center=False).mean()
    std = ratios.rolling(window=window2,
                        center=False).std()
    zscore = (ma1 - ma2)/std
    
    # Simulate trading
    # Start with no money and no positions
    money = 0
    countS1 = 0
    countS2 = 0
    for i in range(len(ratios)):
        # Sell short if the z-score is > 1
        if zscore[i] > 1:
            money += S1[i] - S2[i] * ratios[i]
            countS1 -= 1
            countS2 += ratios[i]
            print('Selling Ratio %s %s %s %s'%(money, ratios[i], countS1,countS2))
        # Buy long if the z-score is < 1
        elif zscore[i] < -1:
            money -= S1[i] - S2[i] * ratios[i]
            countS1 += 1
            countS2 -= ratios[i]
            print('Buying Ratio %s %s %s %s'%(money,ratios[i], countS1,countS2))
        # Clear positions if the z-score between -.5 and .5
        elif abs(zscore[i]) < 0.75:
            money += S1[i] * countS1 + S2[i] * countS2
            countS1 = 0
            countS2 = 0
            print('Exit pos %s %s %s %s'%(money,ratios[i], countS1,countS2))
            
            
    return money
trade(data['ADBE'].iloc[:1763], data['MSFT'].iloc[:1763], 60, 5)

El resultado fue: 1783.375.

Así que esta estrategia parece ser rentable! Ahora, podemos optimizar aún más el rendimiento de los datos de verificación cambiando la ventana de tiempo de media móvil, cambiando el umbral de compra/venta de las posiciones de quietud, etc.

También podemos probar modelos más complejos, como la regresión logística, SVM, etc., para hacer predicciones de 1/-1.

Ahora, vamos a avanzar en este modelo, y eso nos lleva a

Paso 7: Reevalúa los datos de las pruebas

Aquí se menciona la plataforma de cuantificación de los inventores, que utiliza un motor de retroalimentación QPS / TPS de alto rendimiento, una reproducción real del entorno histórico, elimina las trampas comunes de retroalimentación cuantitativa y detecta las deficiencias de la estrategia en el momento oportuno, lo que ayuda a una mejor inversión en la realidad.

En este artículo se explica el principio, o se elige mostrar la lógica subyacente, en su aplicación práctica, o se recomienda a los lectores que utilicen la plataforma de cuantificación de los inventores, además de ahorrar tiempo, lo importante es mejorar la tasa de error.

La repetición es muy simple, podemos usar la función anterior para ver el PnL de los datos de prueba.

trade(data[‘ADBE’].iloc[1762:], data[‘MSFT’].iloc[1762:], 60, 5)

El resultado fue: 5262.868.

El modelo funciona muy bien! Se convirtió en nuestro primer modelo de transacciones de pareja simple.

Evita el exceso de adaptación

Antes de terminar la discusión, me gustaría hablar en particular sobre el exceso de adecuación. El exceso de adecuación es la trampa más peligrosa en las estrategias de negociación. Un algoritmo de exceso de adecuación puede funcionar muy bien en la retroevaluación pero fallar en nuevos datos invisibles, lo que significa que no revela realmente ninguna tendencia en los datos y no tiene una capacidad de predicción real.

En nuestro modelo, usamos la predicción de parámetros de rotación y esperamos optimizar la longitud de la ventana de tiempo por ella. Podemos decidir simplemente repetir todas las posibilidades, una longitud de ventana de tiempo razonable y elegir la longitud de tiempo que mejor se muestre en función de la actuación de nuestro modelo. A continuación, escribimos un sencillo ciclo para calificar la longitud de la ventana de tiempo de pNL según los datos de entrenamiento y encontrar el mejor ciclo.

# Find the window length 0-254 
# that gives the highest returns using this strategy
length_scores = [trade(data['ADBE'].iloc[:1762], 
                data['MSFT'].iloc[:1762], l, 5) 
                for l in range(255)]
best_length = np.argmax(length_scores)
print ('Best window length:', best_length)
('Best window length:', 40)

Ahora que revisamos el rendimiento del modelo en los datos de prueba, descubrimos que la longitud de esta ventana de tiempo no es la óptima!

# Find the returns for test data
# using what we think is the best window length
length_scores2 = [trade(data['ADBE'].iloc[1762:], 
                  data['MSFT'].iloc[1762:],l,5) 
                  for l in range(255)]
print (best_length, 'day window:', length_scores2[best_length])
# Find the best window length based on this dataset, 
# and the returns using this window length
best_length2 = np.argmax(length_scores2)
print (best_length2, 'day window:', length_scores2[best_length2])
(40, 'day window:', 1252233.1395)
(15, 'day window:', 1449116.4522)

Obviamente, los datos de nuestra muestra no siempre producen buenos resultados en el futuro. Sólo para probar, vamos a trazar una fracción de longitud calculada a partir de dos conjuntos de datos.

plt.figure(figsize=(15,7))
plt.plot(length_scores)
plt.plot(length_scores2)
plt.xlabel('Window length')
plt.ylabel('Score')
plt.legend(['Training', 'Test'])
plt.show()

img

Podemos ver que cualquier cosa entre 20 y 50 es una buena opción para la ventana de tiempo.

Para evitar el ajuste excesivo, podemos usar la naturaleza de la racionalización económica o de los algoritmos para elegir la longitud de la ventana de tiempo. También podemos usar el filtro de Kármán, que no requiere que especificemos la longitud; este método se presentará más adelante en otro artículo.

El siguiente paso

En este artículo, ofrecemos algunos sencillos métodos de introducción para demostrar el proceso de desarrollo de estrategias de negociación. En la práctica, se debe utilizar estadísticas más complejas, y se pueden considerar las siguientes opciones:

  • El índice de Hurst

  • Medio de decadencia de la media de regreso deducida del proceso Ornstein-Uhlenbeck

  • El filtro de Kármán


Relacionados

Más.

el fondo bk_No encontré el paquete.

el fondo bk_¿Dónde puedo instalar el backtester.dataSource.yahoo_data_source?