La inspiración para este artículo surgió de la observación de algunas advertencias y trampas comunes después de tratar de aplicar las técnicas de aprendizaje automático a los problemas de transacción durante mi investigación de datos de la plataforma de cuantificación de inventores.
Si aún no has leído mi artículo anterior, te recomendamos que antes de leer este artículo, leas mi Guía de un entorno de investigación de datos automatizados y un método sistemático para desarrollar estrategias de negociación en la plataforma de cuantificación de inventores.
La dirección está aquí:https://www.fmz.com/digest-topic/4187Y tambiénhttps://www.fmz.com/digest-topic/4169 这两篇文章.
Este tutorial está diseñado para aficionados, ingenieros y científicos de datos de todos los niveles de habilidad, ya sea que seas un gran profesional o un pequeño programador, las únicas habilidades que necesitas son un conocimiento básico del lenguaje de programación Python y un conocimiento suficiente de las operaciones de la línea de comandos para poder configurar un proyecto de ciencia de datos.
发明者量化平台FMZ.COM除了提供优质的各大主流交易所的数据源,还提供一套丰富的API接口以帮助我们在完成数据的分析后进行自动化交易。这套接口包括查询账户信息,查询各个主流交易所的高,开,低,收价格,成交量,各种常用技术分析指标等实用工具,特别是对于实际交易过程中连接各大主流交易所的公共API接口,提供了强大的技术支持。
Todas estas características mencionadas anteriormente se envuelven en un sistema similar a Docker, y lo que tenemos que hacer es comprar o alquilar nuestro propio servicio de computación en la nube y luego desplegar el sistema Docker.
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.
Dado que estamos instalando Anaconda en un servicio en la nube, recomendamos que los servidores en la nube instalen una versión de Anaconda para sistemas Linux con línea de comandos.
Para más información sobre cómo instalar Anaconda, consulte el manual oficial de Anaconda:https://www.anaconda.com/distribution/
Si usted es un programador Python experimentado y no siente la necesidad de usar Anaconda, no hay ningún problema.
La salida final de la estrategia de negociación debe responder a las siguientes preguntas:
Dirección: determinar si los activos son baratos, caros o de valor justo.
开仓条件:如果资产价格便宜或者昂贵,你应该做多或者做空.
Transacción en liquidación: si el precio de un activo es razonable y tenemos posiciones en él (compra o venta anterior), ¿deberías liquidarlo?
Rango de precios: el precio (o el rango) para realizar operaciones abiertas
Número: Número de fondos negociados (por ejemplo, número de monedas digitales o número de manos de futuros de productos)
El aprendizaje automático se puede utilizar para responder a cada una de las preguntas anteriores, pero para el resto de este artículo, nos centraremos en responder a la primera pregunta, la dirección del comercio.
En la construcción de estrategias, hay dos tipos de enfoques, uno basado en modelos y otro basado en extracción de datos.
En la construcción de estrategias basadas en modelos, comenzamos con el modelo de baja eficiencia del mercado, construyendo expresiones matemáticas (por ejemplo, precio, ganancia) y probando su eficacia en períodos de tiempo más largos. El modelo es generalmente una versión simplificada de un modelo realmente complejo, que necesita verificar su significado y estabilidad en períodos más largos.
Por otro lado, primero buscamos patrones de precios e intentamos usar algoritmos en el método de extracción de datos. No importa la razón por la que estos patrones se producen, ya que solo se seguirán repitiendo determinados patrones en el futuro. Este es un método de análisis ciego que requiere una inspección rigurosa para identificar los patrones verdaderos a partir de patrones aleatorios.
Obviamente, el aprendizaje automático es fácil de aplicar a métodos de extracción de datos. Veamos cómo usar el aprendizaje automático para crear señales de transacción a través de la extracción de datos.
Los ejemplos de código utilizan herramientas de recuperación basadas en la plataforma de cuantificación de los inventores y interfaces de API de transacciones automatizadas. Después de la implementación completa del administrador y la instalación de Anaconda en la sección anterior, solo necesita instalar la biblioteca de análisis de ciencia de datos que necesitamos y el famoso modelo de aprendizaje automático scikit-learn.
pip install -U scikit-learn
Antes de comenzar, un sistema de problemas estándar de aprendizaje automático se muestra en el siguiente gráfico:
Sistema de problemas de aprendizaje automático
Las características que vamos a crear deben tener alguna capacidad de predicción (X), queremos predecir la variable objetivo (Y), y usar datos históricos para entrenar un modelo ML que pueda predecir Y lo más cerca posible del valor real. Finalmente, usamos este modelo para predecir nuevos datos desconocidos de Y. Esto nos lleva al primer paso:
Es decir, en nuestro marco anterior, ¿qué es Y?
¿Qué quieres predecir?
¿Quieres predecir los precios futuros, los rendimientos futuros/Pnl, señales de compra/venta, optimizar la asignación de la cartera y tratar de ejecutar operaciones de manera eficiente?
Supongamos que tratamos de predecir el precio en la siguiente barra de tiempo. En este caso, Y ((t) = precio ((t + 1)). Ahora podemos completar nuestro marco con los datos históricos.
Observe que Y (t) sólo se conoce en retrospectiva, pero que cuando usamos nuestro modelo no sabremos el precio del tiempo t (t + 1) ; usamos nuestro modelo para predecir Y (t) y solo lo comparamos con el valor real en el tiempo t + 1; esto significa que no puedes usar Y como característica en el modelo de predecir.
Una vez que conocemos el objetivo Y, también podemos decidir cómo evaluar nuestras predicciones. Esto es muy importante para distinguir entre los diferentes modelos de datos con los que vamos a probar. En función del problema que estamos resolviendo, elegir un indicador que mida la eficiencia de nuestro modelo. Por ejemplo, si estamos prediciendo precios, podemos usar el error de raíz uniforme como indicador.
Marco ML para el pronóstico de precios futuros
Para la demostración, vamos a crear un modelo de predicción para predecir el valor de la base futura esperada de un indicador de inversión hipotético, en el que:
basis = Price of Stock — Price of Future
basis(t)=S(t)−F(t)
Y(t) = future expected value of basis = Average(basis(t+1),basis(t+2),basis(t+3),basis(t+4),basis(t+5))
Dado que este es un problema de regresión, evaluaremos el modelo en RMSE (error de raíz cuadrada); también usaremos Total Pnl como criterio de evaluación.
Nota: Para obtener información matemática sobre RMSE, consulte la Enciclopedia.
Recopila y limpia los datos que te ayudan a resolver los problemas que tienes.
¿Cuáles son los datos que necesitas considerar para predecir la variable objetivo Y? Si estamos prediciendo el precio, puedes usar los datos de precios de los indicadores de inversión, los datos de volumen de transacción de los indicadores de inversión, los datos similares de los indicadores de inversión relacionados, los indicadores de equidad del índice de inversión, los indicadores de mercado general, los precios de otros activos relacionados, etc.
Para ello, necesitarás establecer permisos de acceso a los datos y asegurarte de que tus datos son exactos y de que se resuelven los datos perdidos (un problema muy común); al mismo tiempo, debes asegurarte de que tus datos son imparciales y representan adecuadamente todas las condiciones del mercado (por ejemplo, el mismo número de escenarios de pérdidas y ganancias) para evitar que el modelo se desvíe. También puedes necesitar limpiar los datos para obtener dividendos, segmentación de indicadores de inversión, continuidad, etc.
Si usas una plataforma de cuantificación de inventoresFMZ.COMLa plataforma de cuantificación de inventores también limpia y filtra estos datos de antemano, como el desglose de indicadores de inversión y datos de movimiento profundo, y los presenta a los desarrolladores de estrategias en un formato fácil de entender para los trabajadores de la cuantificación.
Para facilitar la demostración de este artículo, utilizamos los siguientes datos como referencia de inversión virtual para las bombas MQK, y también utilizamos una herramienta de cuantificación muy útil llamada Auquan Bombs Toolbox, para obtener más información:https://github.com/Auquan/auquan-toolbox-python
# Load the data
from backtester.dataSource.quant_quest_data_source import QuantQuestDataSource
cachedFolderName = '/Users/chandinijain/Auquan/qq2solver-data/historicalData/'
dataSetId = 'trainingData1'
instrumentIds = ['MQK']
ds = QuantQuestDataSource(cachedFolderName=cachedFolderName,
dataSetId=dataSetId,
instrumentIds=instrumentIds)
def loadData(ds):
data = None
for key in ds.getBookDataByFeature().keys():
if data is None:
data = pd.DataFrame(np.nan, index = ds.getBookDataByFeature()[key].index, columns=[])
data[key] = ds.getBookDataByFeature()[key]
data['Stock Price'] = ds.getBookDataByFeature()['stockTopBidPrice'] + ds.getBookDataByFeature()['stockTopAskPrice'] / 2.0
data['Future Price'] = ds.getBookDataByFeature()['futureTopBidPrice'] + ds.getBookDataByFeature()['futureTopAskPrice'] / 2.0
data['Y(Target)'] = ds.getBookDataByFeature()['basis'].shift(-5)
del data['benchmark_score']
del data['FairValue']
return data
data = loadData(ds)
Con el código anterior, Auquan
¡Este es un paso muy importante!Antes de continuar, debemos dividir los datos en un conjunto de datos de entrenamiento para entrenar a su modelo; un conjunto de datos de prueba para evaluar el rendimiento del modelo. Se recomienda dividirlos en: un conjunto de entrenamiento del 60-70% y un conjunto de pruebas del 30-40%.
Separar los datos en conjuntos de entrenamiento y ensayos
Debido a que los datos de entrenamiento se utilizan para evaluar los parámetros del modelo, es posible que su modelo se sobreajuste a los datos de entrenamiento y que los datos de entrenamiento induzcan a error en el rendimiento del modelo. Si no conserva ningún dato de prueba separado y utiliza todos los datos para entrenar, no sabrá qué tan bien o mal se ejecuta su modelo con respecto a los nuevos datos invisibles. Esta es una de las principales razones por las que los modelos de ML entrenados fallan con los datos en tiempo real: las personas entrenan todos los datos disponibles y se emocionan con los indicadores de los datos de entrenamiento, pero el modelo no puede hacer ninguna predicción significativa sobre los datos en tiempo real que no han sido entrenados.
Separar los datos en conjuntos de entrenamiento, de verificación y de prueba
Este enfoque tiene un problema. Si repetidamente entrenamos los datos de entrenamiento, evaluamos el rendimiento de los datos de prueba y optimizamos nuestro modelo hasta que estamos satisfechos con el rendimiento, implicitamente consideramos los datos de prueba como parte de los datos de entrenamiento. Finalmente, nuestro modelo puede funcionar bien con este conjunto de datos de entrenamiento y prueba, pero no garantiza que pueda predecir bien los nuevos datos.
Para resolver este problema, podemos crear un conjunto de datos de verificación separado. Ahora, puedes entrenar los datos, evaluar el rendimiento de los datos de verificación, optimizarlos hasta que estés satisfecho con el rendimiento, y finalmente probar los datos de prueba.
Recuerde que una vez que haya examinado el rendimiento de los datos de prueba, no vuelva a intentar optimizar el modelo aún más. Si encuentra que su modelo no da buenos resultados, abandone el modelo por completo y comience de nuevo. Se recomienda dividir el 60% de los datos de entrenamiento, el 20% de los datos de verificación y el 20% de los datos de prueba.
Para nuestro problema, tenemos tres conjuntos de datos disponibles, y vamos a usar uno como conjunto de entrenamiento, el segundo como conjunto de verificación, y el tercero como nuestro conjunto de prueba.
# Training Data
dataSetId = 'trainingData1'
ds_training = QuantQuestDataSource(cachedFolderName=cachedFolderName,
dataSetId=dataSetId,
instrumentIds=instrumentIds)
training_data = loadData(ds_training)
# Validation Data
dataSetId = 'trainingData2'
ds_validation = QuantQuestDataSource(cachedFolderName=cachedFolderName,
dataSetId=dataSetId,
instrumentIds=instrumentIds)
validation_data = loadData(ds_validation)
# Test Data
dataSetId = 'trainingData3'
ds_test = QuantQuestDataSource(cachedFolderName=cachedFolderName,
dataSetId=dataSetId,
instrumentIds=instrumentIds)
out_of_sample_test_data = loadData(ds_test)
Para cada uno de estos, agregamos la variable objetivo Y, definida como el promedio de los siguientes cinco valores base.
def prepareData(data, period):
data['Y(Target)'] = data['basis'].rolling(period).mean().shift(-period)
if 'FairValue' in data.columns:
del data['FairValue']
data.dropna(inplace=True)
period = 5
prepareData(training_data, period)
prepareData(validation_data, period)
prepareData(out_of_sample_test_data, period)
Analizar el comportamiento de los datos y crear características predictivas
Ahora comienza la verdadera ingeniería constructiva. La regla de oro de la selección de características es que la predicción proviene principalmente de las características, no del modelo.
No elijas un conjunto de características sin explorar las relaciones con las variables objetivo.
La poca o ninguna relación con las variables objetivo puede causar una adaptación excesiva.
Las características que elijas pueden estar altamente relacionadas entre sí, en este caso, un número menor de características también puede explicar el objetivo.
Generalmente creo algunas características intuitivas para ver cómo las variables de destino se relacionan con esas características y cómo se relacionan entre sí para decidir qué usar.
También puede intentar ordenar las características de los candidatos según el mayor coeficiente informativo (MIC), realizar análisis de componentes principales (PCA) y otros métodos.
Los modelos ML suelen funcionar bien en cuanto a la estandarización. Sin embargo, la estandarización es difícil cuando se trata de datos de secuencias de tiempo, ya que el alcance de los datos futuros es desconocido. Sus datos pueden estar fuera del alcance de la estandarización, lo que causa errores en el modelo.
Escalación: caracterizada por un rango de diferencia estándar o cuadrados
Residencia: menos el promedio histórico del valor actual
Unificación: dos periodos retrospectivos de los anteriores (x - mean) / stdev
Estandarización regular: normaliza los datos en el rango de -1 a +1 y redefine el centro en el período de retroceso ((x-min) / ((max-min))
Tenga en cuenta que debido a que usamos medias continuas históricas, desviación estándar, máximos o mínimos que exceden el período retrogrado, los valores de estandarización de la atribución de las características se representarán en diferentes valores reales en diferentes momentos. Por ejemplo, si el valor actual de la característica es 5, el promedio de 30 ciclos consecutivos es 4.5, y luego se convierte en 0.5 después de que se convierta en 3, el valor de 3.5 se convierte en 0.5 después de que el promedio de 30 ciclos consecutivos se convierta en 3; esto puede ser la causa de los errores del modelo. Por lo tanto, la normalización es complicada y debe averiguar qué es lo que realmente mejora el rendimiento del modelo (si existe).
Para la primera iteración de nuestro problema, hemos creado un gran número de características con parámetros de mezcla. Más adelante intentaremos ver si se puede reducir el número de características.
def difference(dataDf, period):
return dataDf.sub(dataDf.shift(period), fill_value=0)
def ewm(dataDf, halflife):
return dataDf.ewm(halflife=halflife, ignore_na=False,
min_periods=0, adjust=True).mean()
def rsi(data, period):
data_upside = data.sub(data.shift(1), fill_value=0)
data_downside = data_upside.copy()
data_downside[data_upside > 0] = 0
data_upside[data_upside < 0] = 0
avg_upside = data_upside.rolling(period).mean()
avg_downside = - data_downside.rolling(period).mean()
rsi = 100 - (100 * avg_downside / (avg_downside + avg_upside))
rsi[avg_downside == 0] = 100
rsi[(avg_downside == 0) & (avg_upside == 0)] = 0
return rsi
def create_features(data):
basis_X = pd.DataFrame(index = data.index, columns = [])
basis_X['mom3'] = difference(data['basis'],4)
basis_X['mom5'] = difference(data['basis'],6)
basis_X['mom10'] = difference(data['basis'],11)
basis_X['rsi15'] = rsi(data['basis'],15)
basis_X['rsi10'] = rsi(data['basis'],10)
basis_X['emabasis3'] = ewm(data['basis'],3)
basis_X['emabasis5'] = ewm(data['basis'],5)
basis_X['emabasis7'] = ewm(data['basis'],7)
basis_X['emabasis10'] = ewm(data['basis'],10)
basis_X['basis'] = data['basis']
basis_X['vwapbasis'] = data['stockVWAP']-data['futureVWAP']
basis_X['swidth'] = data['stockTopAskPrice'] -
data['stockTopBidPrice']
basis_X['fwidth'] = data['futureTopAskPrice'] -
data['futureTopBidPrice']
basis_X['btopask'] = data['stockTopAskPrice'] -
data['futureTopAskPrice']
basis_X['btopbid'] = data['stockTopBidPrice'] -
data['futureTopBidPrice']
basis_X['totalaskvol'] = data['stockTotalAskVol'] -
data['futureTotalAskVol']
basis_X['totalbidvol'] = data['stockTotalBidVol'] -
data['futureTotalBidVol']
basis_X['emabasisdi7'] = basis_X['emabasis7'] -
basis_X['emabasis5'] +
basis_X['emabasis3']
basis_X = basis_X.fillna(0)
basis_y = data['Y(Target)']
basis_y.dropna(inplace=True)
print("Any null data in y: %s, X: %s"
%(basis_y.isnull().values.any(),
basis_X.isnull().values.any()))
print("Length y: %s, X: %s"
%(len(basis_y.index), len(basis_X.index)))
return basis_X, basis_y
basis_X_train, basis_y_train = create_features(training_data)
basis_X_test, basis_y_test = create_features(validation_data)
Seleccionar el modelo estadístico/ML adecuado según el problema seleccionado
La elección del modelo depende de la forma en que se construye el problema. ¿Estás resolviendo el problema de supervisión (cada punto de la matriz de características X se asigna a la variable objetivo Y) o el problema de aprendizaje sin supervisión (sin una asignación dada, el modelo intenta aprender un patrón desconocido)? ¿Estás resolviendo el problema de regresión (predecir el precio real en el futuro) o el problema de clasificación (sólo predecir la dirección del precio en el futuro) (aumentar/disminuir)?.
Aprendizaje supervisado o no supervisado
Regreso o clasificación
Algunos de los algoritmos de aprendizaje supervisado más comunes pueden ayudarte a empezar:
Regresión lineal (parámetros, regresión)
Regresión logística (parámetros, categorías)
Algorithms de K-neighbor (KNN) basados en casos, regresión
SVM, SVR (parámetros, clasificación y regresión)
El árbol de la decisión
El bosque de la decisión
Yo recomiendo comenzar con un modelo simple, como una regresión lineal o lógica, y construir un modelo más complejo a partir de ahí según sea necesario. También recomiendo que leas las matemáticas detrás del modelo, en lugar de usarlo ciegamente como una caja negra.
Entrene y optimice sus modelos con entrenamiento y verificación de conjuntos de datos
Ahora, usted está listo para construir el modelo final. En esta etapa, usted realmente está solo repitiendo el modelo y los parámetros del modelo. Entrenar su modelo en los datos de entrenamiento, medir su rendimiento en los datos de verificación, y luego volver, optimizar, volver a entrenar y evaluar. Si no está satisfecho con el rendimiento del modelo, pruebe con otros modelos.
Sólo cuando tengas el modelo que más te guste, puedes seguir adelante.
Para nuestro problema de demostración, vamos a empezar con una simple regresión lineal.
from sklearn import linear_model
from sklearn.metrics import mean_squared_error, r2_score
def linear_regression(basis_X_train, basis_y_train,
basis_X_test,basis_y_test):
regr = linear_model.LinearRegression()
# Train the model using the training sets
regr.fit(basis_X_train, basis_y_train)
# Make predictions using the testing set
basis_y_pred = regr.predict(basis_X_test)
# The coefficients
print('Coefficients: \n', regr.coef_)
# The mean squared error
print("Mean squared error: %.2f"
% mean_squared_error(basis_y_test, basis_y_pred))
# Explained variance score: 1 is perfect prediction
print('Variance score: %.2f' % r2_score(basis_y_test,
basis_y_pred))
# Plot outputs
plt.scatter(basis_y_pred, basis_y_test, color='black')
plt.plot(basis_y_test, basis_y_test, color='blue', linewidth=3)
plt.xlabel('Y(actual)')
plt.ylabel('Y(Predicted)')
plt.show()
return regr, basis_y_pred
_, basis_y_pred = linear_regression(basis_X_train, basis_y_train,
basis_X_test,basis_y_test)
Regresión lineal sin unificación
('Coefficients: \n', array([ -1.0929e+08, 4.1621e+07, 1.4755e+07, 5.6988e+06, -5.656e+01, -6.18e-04, -8.2541e-05,4.3606e-02, -3.0647e-02, 1.8826e+07, 8.3561e-02, 3.723e-03, -6.2637e-03, 1.8826e+07, 1.8826e+07, 6.4277e-02, 5.7254e-02, 3.3435e-03, 1.6376e-02, -7.3588e-03, -8.1531e-04, -3.9095e-02, 3.1418e-02, 3.3321e-03, -1.3262e-06, -1.3433e+07, 3.5821e+07, 2.6764e+07, -8.0394e+06, -2.2388e+06, -1.7096e+07]))
Mean squared error: 0.02
Variance score: 0.96
Veamos los coeficientes del modelo. No podemos realmente compararlos o decir cuáles son los que importan, ya que pertenecen a diferentes escalas. Intentemos unificarlos para que cumplan con la misma proporción y también para imponer alguna estabilidad.
def normalize(basis_X, basis_y, period):
basis_X_norm = (basis_X - basis_X.rolling(period).mean())/
basis_X.rolling(period).std()
basis_X_norm.dropna(inplace=True)
basis_y_norm = (basis_y -
basis_X['basis'].rolling(period).mean())/
basis_X['basis'].rolling(period).std()
basis_y_norm = basis_y_norm[basis_X_norm.index]
return basis_X_norm, basis_y_norm
norm_period = 375
basis_X_norm_test, basis_y_norm_test = normalize(basis_X_test,basis_y_test, norm_period)
basis_X_norm_train, basis_y_norm_train = normalize(basis_X_train, basis_y_train, norm_period)
regr_norm, basis_y_pred = linear_regression(basis_X_norm_train, basis_y_norm_train, basis_X_norm_test, basis_y_norm_test)
basis_y_pred = basis_y_pred * basis_X_test['basis'].rolling(period).std()[basis_y_norm_test.index] + basis_X_test['basis'].rolling(period).mean()[basis_y_norm_test.index]
Regresión lineal de la integración
Mean squared error: 0.05
Variance score: 0.90
El modelo no mejora el modelo anterior, pero tampoco lo hace peor. Ahora podemos comparar los coeficientes de hecho y ver qué coeficientes son realmente importantes.
Veamos los coeficientes.
for i in range(len(basis_X_train.columns)):
print('%.4f, %s'%(regr_norm.coef_[i], basis_X_train.columns[i]))
El resultado fue:
19.8727, emabasis4
-9.2015, emabasis5
8.8981, emabasis7
-5.5692, emabasis10
-0.0036, rsi15
-0.0146, rsi10
0.0196, mom10
-0.0035, mom5
-7.9138, basis
0.0062, swidth
0.0117, fwidth
2.0883, btopask
2.0311, btopbid
0.0974, bavgask
0.0611, bavgbid
0.0007, topaskvolratio
0.0113, topbidvolratio
-0.0220, totalaskvolratio
0.0231, totalbidvolratio
Podemos ver claramente que ciertas características tienen un mayor coeficiente que otras y pueden ser más predictivas.
En este artículo, vamos a analizar la relación entre las diferentes características.
import seaborn
c = basis_X_train.corr()
plt.figure(figsize=(10,10))
seaborn.heatmap(c, cmap='RdYlGn_r', mask = (np.abs(c) <= 0.8))
plt.show()
Relación entre características
Las zonas de color rojo oscuro representan variables altamente relevantes. Vamos a crear/modificar algunas características de nuevo y tratar de mejorar nuestro modelo.
例如,我可以轻松地丢弃像emabasisdi7这样的特征,这些特征只是其他特征的线性组合.
def create_features_again(data):
basis_X = pd.DataFrame(index = data.index, columns = [])
basis_X['mom10'] = difference(data['basis'],11)
basis_X['emabasis2'] = ewm(data['basis'],2)
basis_X['emabasis5'] = ewm(data['basis'],5)
basis_X['emabasis10'] = ewm(data['basis'],10)
basis_X['basis'] = data['basis']
basis_X['totalaskvolratio'] = (data['stockTotalAskVol']
- data['futureTotalAskVol'])/
100000
basis_X['totalbidvolratio'] = (data['stockTotalBidVol']
- data['futureTotalBidVol'])/
100000
basis_X = basis_X.fillna(0)
basis_y = data['Y(Target)']
basis_y.dropna(inplace=True)
return basis_X, basis_y
basis_X_test, basis_y_test = create_features_again(validation_data)
basis_X_train, basis_y_train = create_features_again(training_data)
_, basis_y_pred = linear_regression(basis_X_train, basis_y_train, basis_X_test,basis_y_test)
basis_y_regr = basis_y_pred.copy()
('Coefficients: ', array([ 0.03246139,
0.49780982, -0.22367172, 0.20275786, 0.50758852,
-0.21510795, 0.17153884]))
Mean squared error: 0.02
Variance score: 0.96
Mira, el rendimiento de nuestro modelo no ha cambiado, solo necesitamos algunas características para explicar nuestra variable objetivo. Te sugiero que intentes más de las características anteriores, pruebas nuevas combinaciones, etc., y veas qué se puede mejorar en nuestro modelo.
我们还可以尝试更复杂的模型,看看模型的变化是否可以提高性能.
from sklearn import neighbors
n_neighbors = 5
model = neighbors.KNeighborsRegressor(n_neighbors, weights='distance')
model.fit(basis_X_train, basis_y_train)
basis_y_pred = model.predict(basis_X_test)
basis_y_knn = basis_y_pred.copy()
from sklearn.svm import SVR
model = SVR(kernel='rbf', C=1e3, gamma=0.1)
model.fit(basis_X_train, basis_y_train)
basis_y_pred = model.predict(basis_X_test)
basis_y_svr = basis_y_pred.copy()
model=ensemble.ExtraTreesRegressor()
model.fit(basis_X_train, basis_y_train)
basis_y_pred = model.predict(basis_X_test)
basis_y_trees = basis_y_pred.copy()
Compruebe el rendimiento de los datos de la muestra real
Rendimiento de retrospección en el conjunto de datos de prueba (tocado todavía)
Este es el momento crucial. Empezamos a ejecutar nuestro modelo de optimización final desde el último paso de los datos de prueba, y lo dejamos de lado desde el principio, los datos que no hemos tocado hasta ahora.
Esto te da una expectativa realista de cómo tu modelo se ejecutará con datos nuevos y no vistos cuando comiences a operar en tiempo real. Por lo tanto, es necesario asegurarte de tener un conjunto de datos limpio que no se utilice para entrenar o verificar el modelo.
Si no te gustan los resultados de la prueba, desecha el modelo y vuelve a empezar. No vuelvas a optimizar tu modelo, esto puede resultar en una sobreajuste. También se recomienda crear un nuevo conjunto de datos de prueba, ya que este ya está contaminado.
Aquí también vamos a usar la caja de herramientas de Auquan.
import backtester
from backtester.features.feature import Feature
from backtester.trading_system import TradingSystem
from backtester.sample_scripts.fair_value_params import FairValueTradingParams
class Problem1Solver():
def getTrainingDataSet(self):
return "trainingData1"
def getSymbolsToTrade(self):
return ['MQK']
def getCustomFeatures(self):
return {'my_custom_feature': MyCustomFeature}
def getFeatureConfigDicts(self):
expma5dic = {'featureKey': 'emabasis5',
'featureId': 'exponential_moving_average',
'params': {'period': 5,
'featureName': 'basis'}}
expma10dic = {'featureKey': 'emabasis10',
'featureId': 'exponential_moving_average',
'params': {'period': 10,
'featureName': 'basis'}}
expma2dic = {'featureKey': 'emabasis3',
'featureId': 'exponential_moving_average',
'params': {'period': 3,
'featureName': 'basis'}}
mom10dic = {'featureKey': 'mom10',
'featureId': 'difference',
'params': {'period': 11,
'featureName': 'basis'}}
return [expma5dic,expma2dic,expma10dic,mom10dic]
def getFairValue(self, updateNum, time, instrumentManager):
# holder for all the instrument features
lbInstF = instrumentManager.getlookbackInstrumentFeatures()
mom10 = lbInstF.getFeatureDf('mom10').iloc[-1]
emabasis2 = lbInstF.getFeatureDf('emabasis2').iloc[-1]
emabasis5 = lbInstF.getFeatureDf('emabasis5').iloc[-1]
emabasis10 = lbInstF.getFeatureDf('emabasis10').iloc[-1]
basis = lbInstF.getFeatureDf('basis').iloc[-1]
totalaskvol = lbInstF.getFeatureDf('stockTotalAskVol').iloc[-1] - lbInstF.getFeatureDf('futureTotalAskVol').iloc[-1]
totalbidvol = lbInstF.getFeatureDf('stockTotalBidVol').iloc[-1] - lbInstF.getFeatureDf('futureTotalBidVol').iloc[-1]
coeff = [ 0.03249183, 0.49675487, -0.22289464, 0.2025182, 0.5080227, -0.21557005, 0.17128488]
newdf['MQK'] = coeff[0] * mom10['MQK'] + coeff[1] * emabasis2['MQK'] +\
coeff[2] * emabasis5['MQK'] + coeff[3] * emabasis10['MQK'] +\
coeff[4] * basis['MQK'] + coeff[5] * totalaskvol['MQK']+\
coeff[6] * totalbidvol['MQK']
newdf.fillna(emabasis5,inplace=True)
return newdf
problem1Solver = Problem1Solver()
tsParams = FairValueTradingParams(problem1Solver)
tradingSystem = TradingSystem(tsParams)
tradingSystem.startTrading(onlyAnalyze=False,
shouldPlot=True,
makeInstrumentCsvs=False)
Los resultados de las revisiones, Pnl en dólares (Pnl no incluye los costos de transacción y otros gastos)
Verificación por desplazamiento, aprendizaje colectivo, Bagging y Boosting
Además de recopilar más datos, crear mejores características o probar más modelos, hay algunas cosas que puedes intentar mejorar.
1. Verificación por desplazamiento
Verificación por desplazamiento
Las condiciones del mercado rara vez se mantienen invariables. Supongamos que tienes un año de datos y que entrenas con datos de enero a agosto, y que pruebas tu modelo con datos de septiembre a diciembre, es posible que termines entrenando contra un conjunto de condiciones de mercado muy específicas. Tal vez no haya fluctuaciones en el mercado en el primer semestre, algunas noticias extremas causen que el mercado suba drásticamente en septiembre, tu modelo no puede aprender este patrón y te dará predicciones basura.
Es posible que sea mejor intentar una verificación de rodaje avanzada con entrenamiento de enero a febrero, verificación de marzo, reentrenamiento de abril a mayo, verificación de junio, etc.
2. Aprendizaje colectivo
Aprendizaje colectivo
Algunos modelos pueden funcionar muy bien al predecir ciertas situaciones, mientras que otros pueden predecir otras situaciones o en un caso el modelo puede ser extremadamente sobreajustado. Una forma de reducir el error y el sobreajuste es usar conjuntos de diferentes modelos. Su predicción será la media de las predicciones hechas por muchos modelos, y los errores de los diferentes modelos pueden ser neutralizados o reducidos. Algunos métodos de colección comunes son Bagging y Boosting.
Envasado en bolsas
El impulso
Para una breve introducción, voy a saltarme estos métodos, pero puedes encontrar más información en línea.
Vamos a probar un método conjunto para nuestro problema.
basis_y_pred_ensemble = (basis_y_trees + basis_y_svr +
basis_y_knn + basis_y_regr)/4
Mean squared error: 0.02
Variance score: 0.95
Resolver sus problemas
Recolectar datos confiables y limpiarlos
Desglosar los datos en conjuntos de entrenamiento, verificación y prueba
Crear características y analizar su comportamiento
Seleccionar el modelo de entrenamiento adecuado según el comportamiento
Utilice los datos de entrenamiento para entrenar sus modelos y hacer predicciones.
Compruebe y re-optimice el rendimiento de los conjuntos de verificación
Verificar el rendimiento final del conjunto de pruebas
¿No es una buena idea? Pero aún no está terminado, ahora solo tienes un modelo de predicción confiable. ¿Recuerdas lo que realmente queremos en nuestra estrategia?
Desarrollo de señales basadas en modelos de predicción para identificar la dirección de las transacciones
Desarrollar estrategias concretas para identificar las posiciones abiertas
Sistema de ejecución para identificar posiciones y precios
Los inventores pueden utilizar estas herramientas en sus plataformas de cuantificación.FMZ.COMEn Inventor's Quantified Platform, hay muchas estrategias alternativas completas y completas, junto con el método de aprendizaje automático de este artículo, que harán que sus estrategias específicas sean como un tigre. Strategy Square se encuentra en:https://www.fmz.com/square
Información importante sobre los costos de las transacciones:你的模型会告诉你所选资产何时是做多或做空。然而,它没有考虑费用/交易成本/可用交易量/止损等。交易成本通常会使有利可图的交易成为亏损。例如,预期价格上涨0.05美元的资产是买入,但如果你必须支付0.10美元进行此交易,你将最终获得净亏损$0.05。在你考虑经纪人佣金,交换费和点差后,我们上面看起来很棒的盈利图实际上是这样的:
Los resultados de las revisiones después de las tarifas de transacción y de los puntos de diferenciación, Pnl en dólares
¡Las tarifas y las diferencias representan más del 90% de nuestro PNL!
Por último, vamos a ver algunas de las trampas más comunes.
¡Eviten con todas sus fuerzas el exceso de adaptación!
No reentrenar después de cada punto de datos: este es un error común que se comete en el desarrollo de aprendizaje automático. Si su modelo necesita reentrenarse después de cada punto de datos, es probable que no sea un modelo muy bueno. Es decir, necesita reentrenarse regularmente y solo debe entrenarse con una frecuencia razonable (por ejemplo, si se hace una predicción durante el día, se reentrenará al final de la semana).
Evitar la desviación, especialmente la desviación prospectiva: esta es otra razón por la que el modelo no funciona, asegúrese de no usar ninguna información futura. En la mayoría de los casos, esto significa no usar la variable objetivo Y como característica en el modelo. Durante la prueba retrospectiva, puedes usarla, pero no la usarás cuando el modelo se ejecute efectivamente, lo que hará que tu modelo no sea útil.
Vigilante con el desviación de la extracción de datos: ya que estamos tratando de hacer una serie de modelos con nuestros datos para determinar si son adecuados, si no hay una razón especial, asegúrese de que usted ejecuta pruebas estrictas para separar los patrones aleatorios de los patrones reales que pueden ocurrir. Por ejemplo, la regresión lineal explica muy bien los patrones de tendencia ascendente, que probablemente serán solo una pequeña parte de un mayor aleatorio.
Esto es muy importante, y creo que es necesario repetirlo.
El exceso de adecuación es la trampa más peligrosa de la estrategia de negociación.
Un algoritmo complejo puede funcionar muy bien en retrospectiva, pero fracasa en nuevos datos invisibles, que no revelan realmente ninguna tendencia en los datos y no tienen una capacidad de predicción real.
Mantenga su sistema lo más simple posible. Si usted encuentra que necesita una gran cantidad de funciones complejas para interpretar los datos, entonces usted puede ser demasiado adecuado.
Divide tus datos disponibles en datos de entrenamiento y prueba, y siempre verifica el rendimiento de los datos reales de la muestra antes de usar el modelo para realizar transacciones en tiempo real.
Un poco de conocimientoMuchas gracias, papá.
el congcong009Es un gran artículo, ideas y resúmenes para principiantes.
lalademaxia¡Qué arrogante!