No artigo anterior, ele escreveu:https://www.fmz.com/digest-topic/4187No artigo, apresentamos estratégias de negociação de acoplamento e demonstramos como usar dados e análise matemática para criar e automatizar estratégias de negociação.
A estratégia de equilíbrio multi-espaço é uma extensão natural da estratégia de negociação de pares aplicada a um indicador de negociação de uma cesta; é particularmente aplicável a mercados de negociação de várias variedades e inter-relacionados, como o mercado de moeda digital e o mercado de futuros de commodities.
A estratégia de equilíbrio multi-espaço é a de negociar ações em uma cesta de ações em simultâneo; assim como no caso de uma transação em parceria, determina quais ações são baratas e quais são caras. A diferença é que a estratégia de equilíbrio multi-espaço coloca todas as ações em um conjunto de ações para determinar quais ações são relativamente baratas ou caras.
Lembre-se de que nós dissemos antes que o par de negociações é uma estratégia neutra de mercado? O mesmo acontece com a estratégia de equilíbrio de direitos e benefícios, pois o valor de vários pontos e posições vazias garante que a estratégia permaneça neutra do mercado ("indefeita às flutuações do mercado"). A estratégia também é estatisticamente robusta; ao classificar os indicadores de investimento e manter vários pontos, você pode colocar vários posições no seu modelo de classificação, em vez de apenas uma única posição de risco; você está simplesmente apostando na qualidade do seu plano de classificação.
O esquema de classificação é um modelo que permite priorizar cada indicador de acordo com o desempenho esperado. Os fatores podem ser fatores de valor, indicadores técnicos, modelos de preços ou uma combinação de todos os fatores acima. Por exemplo, você pode usar indicadores de momentum para classificar indicadores de investimentos que acompanham uma série de tendências: os indicadores de investimentos com o maior momentum são esperados para continuar bem e obter a maior classificação; os investimentos com o menor momentum apresentam o pior desempenho e o menor retorno.
O sucesso desta estratégia está quase inteiramente no esquema de classificação usado, ou seja, seu esquema de classificação pode separar os indicadores de investimentos de alto desempenho dos indicadores de investimentos de baixo desempenho, melhor realizando o retorno da estratégia de indicadores de investimentos de vários espaços. Portanto, é muito importante criar um esquema de classificação.
Uma vez que definimos um esquema de classificação, é óbvio que queremos lucrar com ele. Fazemos isso investindo a mesma quantidade de dinheiro em um investimento que está na parte superior do ranking e em um investimento que está na parte inferior do ranking. Isso garante que a estratégia só ganhe dinheiro proporcionalmente à qualidade do ranking e seja "neutral no mercado".
Suponha que você esteja classificando todos os indicadores m, com investimentos de n dólares, e que pretenda manter posições com um total de 2p (donde m> 2p). Se o indicador classificado em ranking 1 for o mais pessimista, o indicador classificado em ranking m será o melhor:
Você coloca o valor em uma posição como: 1,..., p, e faz o valor de 2/2p em dólares.
Você coloca a nota em uma posição como m-p, m, e faz uma nota de mais de n/2p dólares.
** Nota: ** Como o preço de um indicador de investimento causado por um salto de preço não é sempre uniformemente dividido em n/2p e é necessário comprar certos indicadores em números inteiros, haverá alguns algoritmos imprecisos que devem se aproximar o máximo possível desse número. Para a estratégia de executar n = 100000 e p = 500, vemos:
n/2p = 100000/1000 = 100
Isso causa um grande problema para os preços com pontuações maiores que 100 (como no mercado de futuros de commodities), porque você não pode abrir posições com pontuações (o mercado de moeda digital não existe); nós aliviamos isso reduzindo os preços de negociação por pontuação ou aumentando o capital.
Primeiro, para que o trabalho prossiga bem, precisamos construir o nosso ambiente de pesquisa, que neste artigo usamos a plataforma de quantificação dos inventores.FMZ.COMO projeto foi desenvolvido para criar um ambiente de pesquisa, principalmente para uma interface API rápida e fácil de usar e um sistema Docker completo para o futuro.
No nome oficial da plataforma de quantificação dos inventores, o sistema Docker é conhecido como sistema administrador.
Para mais informações sobre como implantar administradores e robôs, consulte meu artigo anterior:https://www.fmz.com/bbs-topic/4140
Os leitores que desejam comprar um administrador de instalação de servidores de nuvem podem consultar este artigo:https://www.fmz.com/bbs-topic/2848
Depois de implementarmos com sucesso um bom sistema de serviços e administradores de nuvem, vamos instalar o maior templo do Python até agora: o Anaconda.
Para implementar todos os ambientes de programação necessários para este artigo (dependências, gerenciamento de versões, etc.), o método mais simples é usar o Anaconda. É um ecossistema de ciência de dados Python e um gerenciador de dependências.
Para saber como instalar o Anaconda, consulte o guia oficial do Anaconda:https://www.anaconda.com/distribution/
本文还将用到numpy和pandas这两个目前在Python科学计算方面十分流行且重要的库.
O trabalho básico acima também pode ser referenciado em meu artigo anterior, onde eu expliquei como configurar o ambiente Anaconda e as bibliotecas numpy e pandas.https://www.fmz.com/digest-topic/4169
Nós geramos indicadores de investimento aleatórios e fatores aleatórios para classificá-los. Suponhamos que nossos retornos futuros realmente dependem desses fatores.
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)
Agora que temos o valor fator e o rendimento, podemos ver o que acontece se nós classificamos os indicadores de investimento pelo valor fator, e então abrimos posições de heads e heads vazios.
# 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()
A nossa estratégia é a de colocar mais em primeiro lugar num conjunto de indicadores de investimento; a de não colocar 10 em primeiro lugar.
basket_returns[number_of_baskets-1] - basket_returns[0]
O resultado foi: 4.172.
Colocar o dinheiro no nosso modelo de classificação para que ele possa separar os investidores de baixo desempenho dos de alto desempenho.
Mais adiante neste artigo, discutiremos como avaliar os esquemas de classificação. Os benefícios de ganhar dinheiro com lucros baseados em classificação são que ele não é influenciado pela desordem do mercado, mas pode ser aproveitado.
Nós carregamos dados de 32 ações de diferentes setores do S&P 500 e tentamos ranqueá-las.
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'
Vamos usar um indicador padronizado de potência de um período de um mês como base para a classificação.
## 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
Agora vamos analisar o comportamento de nossas ações para ver como nossas ações funcionam no mercado em nossos fatores de classificação escolhidos.
Ações
Vamos ver como as ações de uma cesta que escolhemos se comportam em nosso modelo de ranking. Para isso, vamos calcular o retorno de uma semana de longo prazo de todas as ações. E então podemos ver a correlação entre o retorno de cada ação uma semana antes e a dinâmica dos 30 dias anteriores.
# 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 as nossas ações retornam a um certo nível! (obviamente, é assim que o universo que escolhemos funciona) Isso nos diz que, se uma ação tiver uma classificação alta na análise de momentum, devemos esperar que ela não se porte bem na próxima semana.
Em seguida, precisamos de ver a correlação entre a nossa pontuação e o retorno prospectivo do mercado como um todo, ou seja, a relação entre a previsão do retorno esperado e o nosso fator de classificação, se os níveis de correlação mais altos podem prever retornos relativos mais baixos, ou vice-versa.
Para fazer isso, nós calculamos a correlação diária entre a movimentação de 30 dias de todas as ações e o retorno de uma semana de distância.
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()
A correlação diária é muito acentuada, mas muito leve (o que é esperado, porque dizemos que todas as ações retornarão em igual valor).
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 a correlação média é novamente um pouco negativa, mas também varia muito a cada mês.
Já tínhamos calculado o retorno de uma cesta de ações retiradas do nosso ranking. Se nós classificamos todas as ações e as dividimos em grupos nn, qual é o retorno médio de cada grupo?
O primeiro passo é criar uma função que fornecerá a média de retorno e o fator de classificação para cada cesta dada por mês.
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
Quando classificamos as ações com base nessa pontuação, calcula-se o retorno médio de cada cesta. Isso deve nos dar uma ideia de como elas se relacionam ao longo de um longo período de tempo.
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 conseguimos separar os que estão no topo e os que estão no baixo.
É claro que essas são apenas as relações médias. Para entender o quão consistente essa relação é e se estamos dispostos a negociar, devemos mudar o modo e a atitude de vê-la ao longo do tempo. Em seguida, vamos olhar para os diferenciais mensais dos dois anos anteriores.
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()
Finalmente, se fizermos mais a última cesta e fizermos a primeira cesta livre a cada mês, então vamos ver o retorno (assumindo que a distribuição de capital de cada título seja igual)
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)
Renda anual: 5.03%
Vemos que temos um esquema de classificação muito fraco, que só distingue moderadamente entre ações de alto desempenho e ações de baixo desempenho. Além disso, o esquema de classificação não é consistente e varia muito mensalmente.
Para implementar uma estratégia de equilíbrio de múltiplos espaços, você só precisa definir o esquema de classificação. Depois disso, tudo é mecânico. Uma vez que você tem uma estratégia de equilíbrio de múltiplos espaços, você pode trocar diferentes fatores de classificação, sem muita mudança.
O esquema de classificação também pode vir de praticamente qualquer modelo. Não é necessariamente um modelo de fatores baseado em valor, mas pode ser uma técnica de aprendizado de máquina que prevê retornos um mês antes e classifica de acordo com esse nível.
O esquema de classificação é a vantagem e o componente mais importante da estratégia de equilíbrio de direitos e interesses.
Um bom ponto de partida é escolher tecnologias já conhecidas e ver se você pode modificá-las um pouco para obter maiores retornos.
Clonagem e adaptaçãoPor exemplo: escolha um assunto que é frequentemente discutido e veja se pode ser modificado um pouco para obter vantagem. Normalmente, os fatores publicados não terão mais sinais de negociação, pois eles estão totalmente aproveitados para o mercado. Mas às vezes eles orientam você na direção certa.
Modelo de preçosQualquer modelo que prevê retornos futuros pode ser um fator e tem potencial potencial para ser usado para classificar seus indicadores de negociação de uma cesta. Você pode usar qualquer modelo de preço complexo e transformá-lo em um esquema de classificação.
Os fatores baseados no preço (indicadores técnicos)Os fatores baseados em preços, como os que discutimos hoje, obtêm informações sobre os preços históricos de cada direito e usam-nas para gerar valores de fatores. Exemplos podem ser indicadores de média móvel, indicadores de força ou indicadores de volatilidade.
Regresso e MovimentoÉ interessante notar que alguns fatores pensam que o preço vai continuar a evoluir uma vez que ele se move em uma direção; outros, exatamente o contrário. Ambos são modelos eficazes sobre diferentes períodos de tempo e ativos, e é importante estudar se o comportamento básico é baseado em movimentação ou em regressão.
Fator básico (baseado em valor)É uma combinação de valores fundamentais, como PE, dividendos, etc. Os valores fundamentais contêm informações relacionadas aos fatos do mundo real da empresa e, portanto, podem ser mais fortes do que o preço em muitos aspectos.
No final das contas, os fatores de prognóstico de crescimento são uma corrida de armas, você está tentando manter-se à frente. Os fatores são desativados do mercado e têm uma vida útil, então você deve trabalhar continuamente para determinar o quanto seus fatores sofreram um declínio e quais novos fatores podem ser usados para substituí-los.
Cada sistema de classificação prevê retornos em intervalos de tempo ligeiramente diferentes. Os retornos de média baseados em preços podem ser previsíveis em dias, enquanto os modelos baseados em fatores de valor podem ser previsíveis em meses. Determinar o intervalo de tempo em que o modelo deve prever é muito importante e fazer uma verificação estatística antes de executar a estratégia.
Cada estratégia possui um volume de capital mínimo e máximo, e o limite mínimo é geralmente determinado pelo custo do negócio.
Negociar muitas ações levará a custos elevados de negociação. Suponha que você queira comprar 1000 ações, então cada reequilíbrio gerará vários milhares de dólares de custos. Sua base de capital deve ser alta o suficiente para que os custos de negociação representem uma fração do retorno gerado pela sua estratégia. Por exemplo, se você tiver US $ 100.000 e sua estratégia ganha 1% por mês (US $ 1000), todos esses retornos serão ocupados pelo custo de negociação.
O limite mínimo de ativos depende principalmente do número de ações negociadas. No entanto, o máximo de capacidade também é muito alto, e a estratégia de equilíbrio multi-espaços é capaz de negociar centenas de milhões de dólares sem perder vantagem. Isso é verdade porque a estratégia é relativamente infrequente para reequilibrar. O total de ativos, além do número de ações negociadas, e o valor em dólares de cada ação são muito baixos, e você não precisa se preocupar com o impacto do seu volume de negociação no mercado.