En el artículo anterior (https://www.fmz.com/bbs-topic/9862), presentamos estrategias de negociación de pares y demostramos cómo crear y automatizar estrategias de negociación mediante el uso de datos y análisis matemático.
La estrategia de equidad equilibrada de posiciones largas y cortas es una extensión natural de la estrategia de negociación de pares aplicable a una cesta de objetos de negociación. Es particularmente adecuada para mercados de negociación con muchas variedades e interrelaciones, como los mercados de divisas digitales y los mercados de futuros de materias primas.
La estrategia de equidad equilibrada de posiciones largas y cortas es ir largo y corto una cesta de objetivos comerciales simultáneamente. Al igual que la negociación de pares, determina qué objetivo de inversión es barato y qué objetivo de inversión es caro. La diferencia es que la estrategia de equidad equilibrada de posiciones largas y cortas organizará todos los objetivos de inversión en un grupo de selección de acciones para determinar qué objetivos de inversión son relativamente baratos o caros. Luego, se largará los n objetivos de inversión superiores basados en el ranking y se cortará los n objetivos de inversión inferiores en la misma cantidad (valor total de posiciones largas = valor total de posiciones cortas).
¿Recuerdas lo que dijimos que el comercio de pares es una estrategia neutral del mercado? Lo mismo es cierto para la estrategia equitativa equilibrada de posiciones cortas largas, porque la cantidad igual de posiciones largas y cortas asegura que la estrategia se mantendrá neutral del mercado (no afectada por las fluctuaciones del mercado). La estrategia también es estadísticamente robusta; Al clasificar los objetivos de inversión y mantener posiciones largas, puedes abrir posiciones en tu modelo de clasificación muchas veces, no solo una posición de apertura de riesgo. Estás apostando puramente por la calidad de tu esquema de clasificación.
El esquema de clasificación es un modelo que puede asignar prioridad a cada sujeto de inversión de acuerdo con el rendimiento esperado. Los factores pueden ser factores de valor, indicadores técnicos, modelos de precios o una combinación de todos los factores anteriores. Por ejemplo, puede usar indicadores de impulso para clasificar una serie de objetivos de inversión de seguimiento de tendencias: se espera que los objetivos de inversión con el mayor impulso continúen funcionando bien y obtengan la clasificación más alta; El objeto de inversión con el menor impulso tiene el peor rendimiento y los rendimientos más bajos.
El éxito de esta estrategia depende casi en su totalidad del esquema de clasificación utilizado, es decir, su esquema de clasificación puede separar el objetivo de inversión de alto rendimiento del objetivo de inversión de bajo rendimiento, para lograr mejor el retorno de la estrategia de objetivos de inversión de posiciones largas y cortas.
Una vez que hemos determinado el esquema de clasificación, esperamos obtener ganancias de él. Lo hacemos invirtiendo la misma cantidad de capital para ir largo los objetivos de inversión superiores y ir corto los objetivos de inversión inferiores. Esto asegura que la estrategia solo obtendrá ganancias en proporción a la calidad del ranking, y será
Supongamos que está clasificando todos los objetivos de inversión m, y tiene n dólares para la inversión, y desea mantener un total de 2p (donde m> 2p) posiciones. Si se espera que el objeto de inversión de clasificación de rango 1 tenga el peor rendimiento, se espera que el objeto de inversión de clasificación m tenga el mejor rendimiento:
Se clasifican los objetos de inversión como: 1,...,p posición, ir corto el objetivo de inversión de 2/2p USD.
Usted clasifica los objetos de inversión como: m-p,...,m posición, ir largo el objetivo de inversión de n/2p USD.
Nota: Debido a que el precio del objeto de inversión causado por la fluctuación de precios no siempre dividirá n/2p de manera uniforme, y algunos objetos de inversión deben comprarse con números enteros, habrá algunos algoritmos inexactos, que deben estar lo más cerca posible de este número.
El valor de las emisiones de gases de efecto invernadero es el valor de las emisiones de gases de efecto invernadero.
Esto causará un gran problema para las puntuaciones con un precio superior a 100 (como el mercado de futuros de productos básicos), porque no se puede abrir una posición con un precio fraccionario (este problema no existe en los mercados de divisas digitales).
En primer lugar, para trabajar sin problemas, necesitamos construir nuestro entorno de investigación.FMZ.COM) para construir nuestro entorno de investigación, principalmente para utilizar la interfaz API conveniente y rápida y el sistema Docker bien empaquetado de esta plataforma más adelante.
En el nombre oficial de la plataforma FMZ Quant, este sistema Docker se llama sistema Docker.
Por favor, consulte mi artículo anterior sobre cómo desplegar un docker y robot:https://www.fmz.com/bbs-topic/9864.
Los lectores que quieran comprar su propio servidor de computación en la nube para implementar dockers pueden consultar este artículo:https://www.fmz.com/digest-topic/5711.
Después de desplegar el servidor de computación en la nube y el sistema de docker con éxito, a continuación instalaremos el artefacto más grande de Python: Anaconda
Para realizar todos los entornos de programa relevantes (bibliotecas de dependencias, gestión de versiones, etc.) requeridos en este artículo, la forma más simple es usar Anaconda.
Para el método de instalación de Anaconda, consulte la guía oficial de Anaconda:https://www.anaconda.com/distribution/.
Este artículo también utilizará numpy y pandas, dos bibliotecas populares e importantes en computación científica de Python.
El trabajo básico anterior también puede referirse a mis artículos anteriores, que introducen cómo configurar el entorno Anaconda y las bibliotecas numpy y pandas.https://www.fmz.com/digest-topic/9863.
Generamos objetivos de inversión aleatorios y factores aleatorios para clasificarlos.
import numpy as np
import statsmodels.api as sm
import scipy.stats as stats
import scipy
import matplotlib.pyplot as plt
import seaborn as sns
import pandas as pd
## PROBLEM SETUP ##
# Generate stocks and a random factor value for them
stock_names = ['stock ' + str(x) for x in range(10000)]
current_factor_values = np.random.normal(0, 1, 10000)
# Generate future returns for these are dependent on our factor values
future_returns = current_factor_values + np.random.normal(0, 1, 10000)
# Put both the factor values and returns into one dataframe
data = pd.DataFrame(index = stock_names, columns=['Factor Value','Returns'])
data['Factor Value'] = current_factor_values
data['Returns'] = future_returns
# Take a look
data.head(10)
Ahora que tenemos los valores de los factores y los rendimientos, podemos ver lo que sucede si clasificamos los objetivos de inversión en función de los valores de los factores y luego abrir posiciones largas y cortas.
# Rank stocks
ranked_data = data.sort_values('Factor Value')
# Compute the returns of each basket with a basket size 500, so total (10000/500) baskets
number_of_baskets = int(10000/500)
basket_returns = np.zeros(number_of_baskets)
for i in range(number_of_baskets):
start = i * 500
end = i * 500 + 500
basket_returns[i] = ranked_data[start:end]['Returns'].mean()
# Plot the returns of each basket
plt.figure(figsize=(15,7))
plt.bar(range(number_of_baskets), basket_returns)
plt.ylabel('Returns')
plt.xlabel('Basket')
plt.legend(['Returns of Each Basket'])
plt.show()
Nuestra estrategia es ir largo de la primera canasta clasificada de los grupos objetivo de inversión; ir corto de la décima canasta clasificada.
basket_returns[number_of_baskets-1] - basket_returns[0]
El resultado es: 4.172
Ponga dinero en nuestro modelo de clasificación para que pueda separar objetivos de inversión de alto rendimiento de objetivos de inversión de bajo rendimiento.
En el resto de este artículo, discutiremos cómo evaluar el esquema de clasificación.
Cargamos datos de 32 acciones de diferentes industrias en el índice S&P 500 e intentamos clasificarlas.
from backtester.dataSource.yahoo_data_source import YahooStockDataSource
from datetime import datetime
startDateStr = '2010/01/01'
endDateStr = '2017/12/31'
cachedFolderName = '/Users/chandinijain/Auquan/yahooData/'
dataSetId = 'testLongShortTrading'
instrumentIds = ['ABT','AKS','AMGN','AMD','AXP','BK','BSX',
'CMCSA','CVS','DIS','EA','EOG','GLW','HAL',
'HD','LOW','KO','LLY','MCD','MET','NEM',
'PEP','PG','M','SWN','T','TGT',
'TWX','TXN','USB','VZ','WFC']
ds = YahooStockDataSource(cachedFolderName=cachedFolderName,
dataSetId=dataSetId,
instrumentIds=instrumentIds,
startDateStr=startDateStr,
endDateStr=endDateStr,
event='history')
price = 'adjClose'
Utilicemos el indicador de impulso estandarizado para un período de un mes como base para la clasificación.
## Define normalized momentum
def momentum(dataDf, period):
return dataDf.sub(dataDf.shift(period), fill_value=0) / dataDf.iloc[-1]
## Load relevant prices in a dataframe
data = ds.getBookDataByFeature()['Adj Close']
#Let's load momentum score and returns into separate dataframes
index = data.index
mscores = pd.DataFrame(index=index,columns=assetList)
mscores = momentum(data, 30)
returns = pd.DataFrame(index=index,columns=assetList)
day = 30
Ahora vamos a analizar el comportamiento de nuestras acciones y ver cómo nuestras acciones operan en el mercado en el factor de clasificación que elegimos.
Comportamiento del stock
Veamos cómo se desempeña nuestra cesta de acciones seleccionada en nuestro modelo de clasificación. Para hacer esto, calculemos el retorno semanal a futuro para todas las acciones. Luego podemos ver la correlación entre el retorno a futuro de 1 semana de cada acción y el impulso de los 30 días anteriores. Las acciones que muestran correlación positiva son seguidores de tendencia, mientras que las acciones que muestran correlación negativa son inversiones medias.
# Calculate Forward returns
forward_return_day = 5
returns = data.shift(-forward_return_day)/data -1
returns.dropna(inplace = True)
# Calculate correlations between momentum and returns
correlations = pd.DataFrame(index = returns.columns, columns = ['Scores', 'pvalues'])
mscores = mscores[mscores.index.isin(returns.index)]
for i in correlations.index:
score, pvalue = stats.spearmanr(mscores[i], returns[i])
correlations[‘pvalues’].loc[i] = pvalue
correlations[‘Scores’].loc[i] = score
correlations.dropna(inplace = True)
correlations.sort_values('Scores', inplace=True)
l = correlations.index.size
plt.figure(figsize=(15,7))
plt.bar(range(1,1+l),correlations['Scores'])
plt.xlabel('Stocks')
plt.xlim((1, l+1))
plt.xticks(range(1,1+l), correlations.index)
plt.legend(['Correlation over All Data'])
plt.ylabel('Correlation between %s day Momentum Scores and %s-day forward returns by Stock'%(day,forward_return_day));
plt.show()
¡Todas nuestras acciones tienen una reversión media hasta cierto punto! (Obviamente, el universo que elegimos funciona así.) Esto nos dice que si las acciones se encuentran en el primer lugar en el análisis de impulso, debemos esperar que tengan un desempeño pobre la próxima semana.
A continuación, necesitamos ver la correlación entre nuestros puntajes de clasificación y los rendimientos globales del mercado, es decir, la relación entre la tasa de rendimiento prevista y nuestro factor de clasificación. ¿Puede un nivel de correlación más alto predecir un rendimiento relativo más bajo, o viceversa?
Para este propósito, calculamos la correlación diaria entre el impulso de 30 días de todas las acciones y el retorno a plazo de 1 semana.
correl_scores = pd.DataFrame(index = returns.index.intersection(mscores.index), columns = ['Scores', 'pvalues'])
for i in correl_scores.index:
score, pvalue = stats.spearmanr(mscores.loc[i], returns.loc[i])
correl_scores['pvalues'].loc[i] = pvalue
correl_scores['Scores'].loc[i] = score
correl_scores.dropna(inplace = True)
l = correl_scores.index.size
plt.figure(figsize=(15,7))
plt.bar(range(1,1+l),correl_scores['Scores'])
plt.hlines(np.mean(correl_scores['Scores']), 1,l+1, colors='r', linestyles='dashed')
plt.xlabel('Day')
plt.xlim((1, l+1))
plt.legend(['Mean Correlation over All Data', 'Daily Rank Correlation'])
plt.ylabel('Rank correlation between %s day Momentum Scores and %s-day forward returns'%(day,forward_return_day));
plt.show()
Las correlaciones diarias muestran una correlación muy compleja pero muy leve (que se espera ya que dijimos que todas las acciones volverán a la media).
monthly_mean_correl =correl_scores['Scores'].astype(float).resample('M').mean()
plt.figure(figsize=(15,7))
plt.bar(range(1,len(monthly_mean_correl)+1), monthly_mean_correl)
plt.hlines(np.mean(monthly_mean_correl), 1,len(monthly_mean_correl)+1, colors='r', linestyles='dashed')
plt.xlabel('Month')
plt.xlim((1, len(monthly_mean_correl)+1))
plt.legend(['Mean Correlation over All Data', 'Monthly Rank Correlation'])
plt.ylabel('Rank correlation between %s day Momentum Scores and %s-day forward returns'%(day,forward_return_day));
plt.show()
Podemos ver que la correlación promedio es ligeramente negativa de nuevo, pero también cambia mucho cada mes.
Hemos calculado el rendimiento de una cesta de acciones tomadas de nuestro ranking.
El primer paso es crear una función que dará el rendimiento promedio y el factor de clasificación de cada canasta dada cada mes.
def compute_basket_returns(factor, forward_returns, number_of_baskets, index):
data = pd.concat([factor.loc[index],forward_returns.loc[index]], axis=1)
# Rank the equities on the factor values
data.columns = ['Factor Value', 'Forward Returns']
data.sort_values('Factor Value', inplace=True)
# How many equities per basket
equities_per_basket = np.floor(len(data.index) / number_of_baskets)
basket_returns = np.zeros(number_of_baskets)
# Compute the returns of each basket
for i in range(number_of_baskets):
start = i * equities_per_basket
if i == number_of_baskets - 1:
# Handle having a few extra in the last basket when our number of equities doesn't divide well
end = len(data.index) - 1
else:
end = i * equities_per_basket + equities_per_basket
# Actually compute the mean returns for each basket
#s = data.index.iloc[start]
#e = data.index.iloc[end]
basket_returns[i] = data.iloc[int(start):int(end)]['Forward Returns'].mean()
return basket_returns
Cuando clasificamos las acciones en base a este puntaje, calculamos el rendimiento promedio de cada canasta. Esto debería permitirnos comprender su relación durante mucho tiempo.
number_of_baskets = 8
mean_basket_returns = np.zeros(number_of_baskets)
resampled_scores = mscores.astype(float).resample('2D').last()
resampled_prices = data.astype(float).resample('2D').last()
resampled_scores.dropna(inplace=True)
resampled_prices.dropna(inplace=True)
forward_returns = resampled_prices.shift(-1)/resampled_prices -1
forward_returns.dropna(inplace = True)
for m in forward_returns.index.intersection(resampled_scores.index):
basket_returns = compute_basket_returns(resampled_scores, forward_returns, number_of_baskets, m)
mean_basket_returns += basket_returns
mean_basket_returns /= l
print(mean_basket_returns)
# Plot the returns of each basket
plt.figure(figsize=(15,7))
plt.bar(range(number_of_baskets), mean_basket_returns)
plt.ylabel('Returns')
plt.xlabel('Basket')
plt.legend(['Returns of Each Basket'])
plt.show()
Parece que podemos separar a los de alto rendimiento de los de bajo rendimiento.
Por supuesto, estas son solo relaciones promedio. Para entender cuán consistente es la relación y si estamos dispuestos a operar, debemos cambiar nuestro enfoque y actitud hacia ella con el tiempo. A continuación, veremos su margen de interés mensual (base) para los dos años anteriores. Podemos ver más cambios y realizar un análisis adicional para determinar si este puntaje de impulso se puede operar.
total_months = mscores.resample('M').last().index
months_to_plot = 24
monthly_index = total_months[:months_to_plot+1]
mean_basket_returns = np.zeros(number_of_baskets)
strategy_returns = pd.Series(index = monthly_index)
f, axarr = plt.subplots(1+int(monthly_index.size/6), 6,figsize=(18, 15))
for month in range(1, monthly_index.size):
temp_returns = forward_returns.loc[monthly_index[month-1]:monthly_index[month]]
temp_scores = resampled_scores.loc[monthly_index[month-1]:monthly_index[month]]
for m in temp_returns.index.intersection(temp_scores.index):
basket_returns = compute_basket_returns(temp_scores, temp_returns, number_of_baskets, m)
mean_basket_returns += basket_returns
strategy_returns[monthly_index[month-1]] = mean_basket_returns[ number_of_baskets-1] - mean_basket_returns[0]
mean_basket_returns /= temp_returns.index.intersection(temp_scores.index).size
r = int(np.floor((month-1) / 6))
c = (month-1) % 6
axarr[r, c].bar(range(number_of_baskets), mean_basket_returns)
axarr[r, c].xaxis.set_visible(False)
axarr[r, c].set_title('Month ' + str(month))
plt.show()
plt.figure(figsize=(15,7))
plt.plot(strategy_returns)
plt.ylabel('Returns')
plt.xlabel('Month')
plt.plot(strategy_returns.cumsum())
plt.legend(['Monthly Strategy Returns', 'Cumulative Strategy Returns'])
plt.show()
Por último, si vamos largo la última canasta y corto la primera canasta cada mes, entonces vamos a mirar los rendimientos (suponiendo la misma asignación de capital por valor).
total_return = strategy_returns.sum()
ann_return = 100*((1 + total_return)**(12.0 /float(strategy_returns.index.size))-1)
print('Annual Returns: %.2f%%'%ann_return)
Tasa de rendimiento anual: 5,03%
Podemos ver que tenemos un esquema de clasificación muy débil, que sólo puede distinguir suavemente las acciones de alto rendimiento de las de bajo rendimiento. Además, este esquema de clasificación no es coherente y varía mucho cada mes.
Para realizar la estrategia de equidad equilibrada a corto y largo plazo, en realidad, solo necesita determinar el esquema de clasificación. Todo después de eso es mecánico. Una vez que tenga una estrategia de equidad equilibrada a corto y largo plazo, puede intercambiar diferentes factores de clasificación sin mucho cambio. Es una manera muy conveniente de iterar sus ideas rápidamente sin preocuparse por ajustar todo el código cada vez.
El esquema de clasificación también puede provenir de casi cualquier modelo. No es necesariamente un modelo de factores basado en el valor. Puede ser una tecnología de aprendizaje automático que puede predecir los rendimientos con un mes de anticipación y clasificar de acuerdo con este nivel.
El esquema de clasificación es la ventaja y la parte más importante de la estrategia de equidad equilibrada a corto y largo plazo.
Un buen punto de partida es seleccionar las tecnologías conocidas existentes y ver si se pueden modificar ligeramente para obtener mayores rendimientos.
Clonar y ajustar: elige un tema que se discute a menudo, y mira si puedes modificarlo ligeramente para obtener ventajas.
Modelo de precios: Cualquier modelo que predice los rendimientos futuros puede ser un factor que potencialmente se puede utilizar para clasificar su cesta de objetos comerciales.
Factores basados en el precio (indicadores técnicos): los factores basados en el precio, como se discute hoy, obtienen información sobre el precio histórico de cada acción y lo utilizan para generar valores de factores.
Regresión e impulso: Vale la pena señalar que algunos factores creen que una vez que los precios se mueven en una dirección, seguirán haciéndolo, mientras que algunos factores son justo lo contrario. Ambos son modelos efectivos para diferentes horizontes temporales y activos, y es importante estudiar si el comportamiento básico se basa en impulso o regresión.
Factor básico (basado en el valor): Esta es una combinación de valores básicos, como PE, dividendos, etc. El valor básico contiene información relacionada con los hechos del mundo real de la empresa, por lo que puede ser más poderoso que el precio en muchos aspectos.
En última instancia, el predictor de desarrollo es una carrera armamentista, y usted está tratando de mantenerse un paso adelante. Los factores serán arbitraje del mercado y tienen una vida útil, por lo que debe trabajar constantemente para determinar cuántas recesiones sus factores han experimentado y qué nuevos factores se pueden utilizar para reemplazarlos.
Cada sistema de clasificación predice rendimientos en un marco de tiempo ligeramente diferente. La regresión media basada en el precio puede ser predecible en unos pocos días, mientras que el modelo de factores basado en el valor puede ser predictivo en unos pocos meses. Es importante determinar el rango de tiempo que el modelo debe predecir y realizar una verificación estadística antes de ejecutar la estrategia. Por supuesto, no desea sobreajustarse tratando de optimizar la frecuencia de reequilibrio.
Cada estrategia tiene el volumen de capital mínimo y máximo, y el umbral mínimo se determina generalmente por el costo de la transacción.
El comercio de demasiadas acciones llevará a altos costos de transacción. Si desea comprar 1,000 acciones, costará miles de dólares en cada reequilibrio. Su base de capital debe ser lo suficientemente alta como para que los costos de transacción puedan representar una pequeña parte de los retornos que genera su estrategia. Por ejemplo, si su capital es de $ 100,000 y su estrategia gana 1% ($ 1,000) por mes, todos estos retornos serán consumidos por los costos de transacción. Necesita ejecutar la estrategia con millones de dólares de capital para ganar más de 1,000 acciones.
El umbral de activos más bajo depende principalmente del número de acciones negociadas. Sin embargo, la capacidad máxima también es muy alta. La estrategia de equidad equilibrada a largo plazo puede operar cientos de millones de dólares sin perder la ventaja. Esto es un hecho, porque esta estrategia es relativamente infrecuente para el reequilibrio. El valor en dólares de cada acción será muy bajo cuando los activos totales se dividen por el número de acciones negociadas. No tiene que preocuparse por si su volumen de operaciones afectará al mercado. Supongamos que usted negocia 1.000 acciones, es decir, 100.000.000 dólares. Si reequilibra toda la cartera cada mes, cada acción solo operará 100.000 dólares al mes, lo que no es suficiente para ser un mercado importante para la mayoría de los valores.