Aplicações de tecnologia de aprendizagem de máquina em transações

Autora:Bem-estar, Criado: 2019-08-29 09:42:00, Atualizado: 2023-10-19 21:02:44

img

A inspiração para este artigo veio da observação de alguns avisos e armadilhas comuns após tentar aplicar a tecnologia de aprendizado de máquina a problemas de transação durante um estudo de dados sobre plataformas de quantificação de inventores.

Se você ainda não leu o meu artigo anterior, recomendamos que você leia o meu Guia do Ambiente de Pesquisa de Dados Automatizados e Métodos Sistêmicos para Desenvolver Estratégias de Negociação, construído pela Inventor Quantitative Platform, antes deste artigo.

O endereço é aqui:https://www.fmz.com/digest-topic/4187E tambémhttps://www.fmz.com/digest-topic/4169 这两篇文章.

Construção de um ambiente de pesquisa

Este tutorial é destinado a amadores, engenheiros e cientistas de dados de todos os níveis de habilidade. Se você é um robô da indústria ou um programador novato, a única habilidade necessária é um conhecimento básico da linguagem de programação Python e conhecimento suficiente das operações da linha de comando (para montar um projeto de ciência de dados).

  • Instale o Inventor Quantify Host e configure o Anaconda

发明者量化平台FMZ.COM除了提供优质的各大主流交易所的数据源,还提供一套丰富的API接口以帮助我们在完成数据的分析后进行自动化交易。这套接口包括查询账户信息,查询各个主流交易所的高,开,低,收价格,成交量,各种常用技术分析指标等实用工具,特别是对于实际交易过程中连接各大主流交易所的公共API接口,提供了强大的技术支持。

Todos os recursos mencionados acima estão embutidos em um sistema semelhante ao Docker, o que precisamos fazer é comprar ou alugar o nosso próprio serviço de nuvem e implementar o sistema Docker.

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.

Como estamos instalando o Anaconda em um serviço em nuvem, recomendamos que o servidor em nuvem instale o Anaconda em uma versão de linha de comando do sistema Linux.

Para saber como instalar o Anaconda, consulte o guia oficial do Anaconda:https://www.anaconda.com/distribution/

Se você é um programador Python experiente e sente que não precisa usar o Anaconda, não há problema nenhum. Eu vou assumir que você não precisa de ajuda para instalar dependências necessárias.

Desenvolver estratégias de negociação

A saída final da estratégia de negociação deve responder às seguintes perguntas:

  • Direção: determinar se o ativo é barato, caro ou de valor justo.

  • 开仓条件:如果资产价格便宜或者昂贵,你应该做多或者做空.

  • Negociação de equilíbrio: se o preço do ativo é razoável e temos posições nesse ativo (compras ou vendas anteriores), você deve equilibrar?

  • Intervalo de preços: preço para negociação aberta (ou intervalo)

  • Quantidade: quantidade de fundos negociados (por exemplo, quantidade de moeda digital ou número de mãos de futuros de commodities)

A aprendizagem de máquina pode ser usada para responder a cada uma das perguntas acima, mas para o resto deste artigo, vamos nos concentrar em responder à primeira pergunta, a direção do negócio.

Métodos estratégicos

Para construir estratégias, existem dois tipos de métodos, um baseado em modelos e outro baseado em mineração de dados.

Na construção de estratégias baseadas em modelos, começamos com um modelo de baixa eficiência do mercado, construindo expressões matemáticas (como preço, rendimento) e testando sua eficácia em períodos de tempo mais longos. O modelo é geralmente uma versão simplificada de um modelo realmente complexo, que precisa de ser comprovado para o seu significado e estabilidade em períodos mais longos.

Por outro lado, primeiro procuramos padrões de preços e tentamos usar algoritmos em métodos de mineração de dados. A razão pela qual esses padrões são causados não importa, pois somente padrões definidos continuarão a ser repetidos no futuro. Este é um método de análise cega, que requer um exame rigoroso para identificar padrões verdadeiros a partir de padrões aleatórios.

Obviamente, o aprendizado de máquina é facilmente aplicado a métodos de mineração de dados. Vejamos como usar o aprendizado de máquina para criar sinais de transação através da mineração de dados.

Os exemplos de código usam ferramentas de retorno baseadas em plataformas de quantificação de inventores e interfaces de API de transações automatizadas. Após a implementação completa do administrador e a instalação do Anaconda na seção acima, basta instalar o banco de dados de análise de ciência de dados que precisamos e o famoso modelo de aprendizado de máquina scikit-learn.

pip install -U scikit-learn

Criar sinais de estratégia de negociação usando aprendizado de máquina

  • Mineração de dados

Antes de começarmos, um sistema padrão de problemas de aprendizagem de máquina é mostrado no gráfico abaixo:

img

Sistema de problemas de aprendizagem de máquina

Os caracteres que vamos criar devem ter alguma capacidade de previsão (X), queremos prever a variável alvo (Y) e usar dados históricos para treinar um modelo ML que possa prever Y o mais próximo possível do valor real. Finalmente, usamos esse modelo para fazer previsões sobre novos dados desconhecidos sobre Y. Isso nos leva ao primeiro passo:

Primeiro passo: Configure o seu problema

  • O que você quer prever? O que é uma boa previsão? Como você avalia os resultados da previsão?

Ou seja, no quadro acima, o que é Y?

img

O que você quer prever?

Quer prever preços futuros, retornos/PNL futuros, sinais de compra/venda, optimizar a distribuição de portfólios e tentar executar transações de forma eficiente?

Suponhamos que tentemos prever o preço no próximo fuso horário. Neste caso, Y ((t) = preço ((t + 1)). Agora podemos concluir nosso quadro com dados históricos.

Observe que Y (t) é conhecido somente na retrospecção, mas quando usamos nosso modelo, não saberemos o preço do tempo t (t + 1) ; usamos nosso modelo para prever Y (t) e só o comparamos ao valor real no tempo t + 1; isso significa que você não pode usar Y como uma característica no modelo de previsão.

Uma vez que conhecemos o objetivo Y, também podemos decidir como avaliar nossas previsões. Isso é muito importante para distinguir os diferentes modelos com os quais vamos tentar os dados. Dependendo do problema que estamos resolvendo, escolha um indicador que meça a eficiência do nosso modelo. Por exemplo, se estamos prevendo preços, podemos usar o erro da raiz uniforme como indicador.

img

Ml framework para prever preços futuros

Para demonstrar, vamos criar um modelo de previsão para prever o valor de uma referência base futura esperada de um indicador de investimento hipotético, onde:

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

Como este é um problema de regressão, vamos avaliar o modelo no RMSE (erro da raiz quadrada); também vamos usar Total Pnl como critério de avaliação.

Nota: Para saber mais sobre o RMSE, consulte o enciclopédia.

  • 我们的目标:创建一个模型,使预测值尽可能接近Y.

Segundo passo: coletar dados confiáveis

Coletar e limpar dados que ajudam a resolver os problemas em questão

Se nós fizermos a previsão do preço, você pode usar os dados de preço do indicador do investimento, os dados de volume de negociação do indicador do investimento, os dados semelhantes do indicador do investimento, os indicadores do indicador do equilíbrio do indicador do investimento, os indicadores do mercado geral, os preços de outros ativos relacionados, etc.

Você precisa configurar permissões de acesso a dados para isso, e certifique-se de que seus dados são precisos e incorrigíveis, e resolva os dados perdidos ("problemas muito comuns") e certifique-se de que seus dados são imparciais e representam adequadamente todas as condições do mercado ("por exemplo, o mesmo número de cenários de ganhos e perdas) para evitar desvios no modelo. Você também pode precisar de limpar os dados para obter dividendos, divisões de indicadores de investimento, continuidade, etc.

Se você está usando a plataforma de quantificação de inventores.FMZ.COMA plataforma de quantificação dos inventores também limpa e filtra esses dados, como o desdobramento de indicadores de investimento e dados de mercado profundo, e apresenta-os aos desenvolvedores de estratégias em um formato fácil de entender para os trabalhadores de quantificação.

Para facilitar a demonstração deste artigo, usamos os seguintes dados como um parâmetro de investimento virtual para a Auquan MQK, e também usamos uma ferramenta de quantificação muito conveniente chamada Auquan Parâmetros Toolbox, para mais informações, consulte: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)

Com o código acima, a Auquans Toolbox já baixou e carregou os dados para o dicionário de blocos de dados. Agora precisamos preparar os dados no formato que preferimos. A função ds.getBookDataByFeature () retorna o dicionário dos blocos de dados, cada característica um bloco de dados. Criamos novos blocos de dados para ações com todas as características.

Passo 3: Segmentação dos dados

  • Criar conjuntos de treinamento a partir de dados, cruzar-os e testá-los

É um passo muito importante!Antes de continuarmos, devemos dividir os dados em conjuntos de dados de treinamento para treinar seu modelo; conjuntos de dados de teste para avaliar o desempenho do modelo.

img

Dividir os dados em conjuntos de treinamento e de teste

Como os dados de treinamento são usados para avaliar os parâmetros do modelo, seu modelo pode se adaptar demais a esses dados de treinamento, e os dados de treinamento podem confundir o desempenho do modelo. Se você não manter nenhum dado de teste separado e usar todos os dados para treinar, você não saberá o quão bem ou mal seu modelo executa em relação aos novos dados invisíveis. Esta é uma das principais razões pelas quais os modelos de ML treinados falham com dados em tempo real: as pessoas treinam todos os dados disponíveis e ficam animadas com os indicadores dos dados de treinamento, mas o modelo não consegue fazer nenhuma previsão significativa sobre dados em tempo real que não foram treinados.

img

Dividir os dados em conjuntos de treinamento, de verificação e de teste

Essa abordagem apresenta problemas. Se repetidamente treinamos dados de treinamento, avaliamos o desempenho dos dados de teste e otimizamos nosso modelo até que estejamos satisfeitos com o desempenho, implicitamente consideramos os dados de teste como parte dos dados de treinamento. Finalmente, nosso modelo pode funcionar bem com esse conjunto de dados de treinamento e teste, mas não pode garantir que ele possa prever os novos dados muito bem.

Para resolver este problema, podemos criar um conjunto de dados de verificação separado. Agora, você pode treinar os dados, avaliar o desempenho dos dados de verificação, otimizar até que esteja satisfeito com o desempenho e, finalmente, testar os dados de teste. Dessa forma, os dados de teste não são contaminados e não usamos nenhuma informação dos dados de teste para melhorar nosso modelo.

Lembre-se de que, uma vez que o desempenho dos dados de teste tenha sido examinado, não volte atrás para tentar otimizar o modelo ainda mais. Se você descobrir que seu modelo não está dando bons resultados, desista do modelo completamente e recomece. Sugere-se que a divisão seja de 60% de dados de treinamento, 20% de dados de verificação e 20% de dados de teste.

Para o nosso problema, temos três conjuntos de dados disponíveis, vamos usar um como conjunto de treinamento, o segundo como conjunto de verificação e o terceiro como nosso conjunto de teste.

# 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 uma dessas, adicionamos a variável alvo Y, definida como a média dos próximos cinco valores de 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)

Passo 4: Projetos de Características

Analisar o comportamento dos dados e criar características previsíveis

Agora começa a verdadeira engenharia de construção. A regra de ouro da seleção de características é que a capacidade de previsão vem principalmente das características, e não do modelo. Você descobrirá que a seleção de características tem um impacto muito maior no desempenho do que a seleção do modelo.

  • Não escolha um conjunto de características sem explorar a relação com a variável alvo.

  • Pouca ou nenhuma relação com a variável alvo pode levar a uma adaptação excessiva

  • As características que você escolhe podem estar altamente relacionadas umas com as outras, e nesse caso, um número menor de características também pode explicar o objetivo.

  • Eu geralmente criei algumas características intuitivas para ver como as variáveis-alvo se relacionam com essas características e como elas se relacionam entre si para decidir quais usar.

  • Você também pode tentar classificar as características do candidato com base no maior coeficiente de informação (MIC), realizar análise de componentes principais (PCA) e outros métodos.

Transformação/normalização de características:

Os modelos de ML tendem a ter um bom desempenho em padronização. No entanto, a padronização é difícil quando se trata de dados de sequência de tempo, pois o alcance dos dados futuros é desconhecido. Os seus dados podem estar fora do alcance padronizado, o que pode causar erros no modelo.

  • Escala: caracterizada por um intervalo de diferença padrão ou de quatro dígitos

  • Residência: subtraindo a média histórica do valor atual

  • Unificação: dois períodos retrógrados de ((x - mean) / stdev acima

  • Atribuição convencional: padronização dos dados para um intervalo de -1 a +1 e redefinição do centro no período de retrocesso ((x-min) / ((max-min))

Observe que, como usamos médias históricas contínuas, desvio padrão, máximos ou mínimos que ultrapassam o período retrogrado, o valor padronizado da atribuição de uma característica será representado em diferentes valores reais em diferentes épocas. Por exemplo, se o valor atual da característica for 5, a média de 30 ciclos consecutivos é de 4.5, e depois é convertida para 0.5; depois, se a média de 30 ciclos consecutivos for 3, o valor será de 3.5 e será de 0.5; isso pode ser o motivo do erro do modelo.

Para a primeira iteração do nosso problema, nós criamos um grande número de características usando um parâmetro de mistura. Mais tarde vamos tentar ver se podemos reduzir o 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)

Passo 5: Seleção do modelo

Escolha o modelo estatístico/ML apropriado com base na questão escolhida

A escolha do modelo depende da forma como o problema é construído. Você está resolvendo o problema de supervisão (cada ponto X na matriz de características é mapeado para a variável alvo Y) ou o problema de aprendizagem não-supervisionada (não há um mapeamento dado, o modelo tenta aprender um padrão desconhecido)?

img

Aprendizagem supervisionada ou não supervisionada

img

Regresso or Classificação

Alguns algoritmos comuns de aprendizagem supervisionada podem ajudá-lo a começar:

  • Regressão linear (parâmetros, regressão)

  • Regresso logístico (parâmetros, classificação)

  • Algoritmos K-neighbor (KNN) (baseados em exemplos, regressão)

  • SVM, SVR (parâmetros, classificação e regressão)

  • Árvore de decisão

  • Floresta de decisão

Eu recomendo que você comece com um modelo simples, como uma regressão linear ou lógica, e construa um modelo mais complexo a partir daí, conforme necessário. Também recomendo que você leia a matemática por trás do modelo, em vez de usá-lo como uma caixa preta.

Passo 6: treinar, verificar e otimizar (repetir os passos 4-6)

img

Treinar e otimizar o seu modelo com treinamento e verificação de datas.

Agora, você está pronto para construir o modelo final. Nesta fase, você realmente está apenas repetindo o modelo e os parâmetros do modelo. Treinar seu modelo com dados de treinamento, medir seu desempenho com dados de verificação e depois voltar, otimizar, treinar novamente e avaliar. Se você não está satisfeito com o desempenho do modelo, tente outro modelo.

Só depois de ter o modelo que você gosta e seguir para o próximo passo.

Para o nosso problema de demonstração, vamos começar com uma simples regressão linear.

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)

img

Regresso linear sem unificação

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

Veja os coeficientes do modelo. Não podemos realmente compará-los ou dizer quais são os que são importantes, porque eles pertencem a escalas diferentes. Vamos tentar unificar para que eles se ajustem à mesma proporção e também impor alguma estabilidade.

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]

img

Regresso linear da integração

Mean squared error: 0.05
Variance score: 0.90

O modelo não melhorou o modelo anterior, mas não piorou. Agora podemos comparar fatores de fato e ver quais fatores realmente são importantes.

Vamos ver os coeficientes.

for i in range(len(basis_X_train.columns)):
    print('%.4f, %s'%(regr_norm.coef_[i], basis_X_train.columns[i]))

O resultado foi:

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 algumas características têm coeficientes mais elevados do que outras e podem ser mais fortes no seu poder de previsão.

A partir daí, a pesquisa mostra que a maioria dos indivíduos tem uma doença de Alzheimer, que pode ser causada por uma doença de Alzheimer.

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

img

Relacionamento entre características

As áreas vermelhas escuras representam as variáveis altamente relacionadas. Vamos criar/modificar algumas características novamente e tentar melhorar nosso 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()

img

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

Veja, o desempenho do nosso modelo não mudou, só precisamos de algumas características para explicar a nossa variável alvo. Eu recomendo que você experimente mais características acima, experimente novas combinações, etc., para ver o que pode melhorar o nosso modelo.

我们还可以尝试更复杂的模型,看看模型的变化是否可以提高性能.

  • Algoritmos K-neighbor (KNN)
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()

img

  • SVR
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()

img

  • Árvore de decisão
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()

img

Passo 7: Reavaliação dos dados do teste

Verificar o desempenho dos dados reais da amostra

img

Desempenho do retest no conjunto de dados de teste (ainda não tocado)

Este é o momento crítico. Começamos a executar nosso modelo de otimização final a partir do último passo dos dados de teste, e colocamos isso de lado no início, dados que ainda não foram tocados.

Isso fornece-lhe uma expectativa realista de como seu modelo executará com dados novos e invisíveis quando você começar a negociar em tempo real. Portanto, é necessário garantir que você tenha um conjunto de dados limpo que não seja usado para treinar ou verificar o modelo.

Se você não gosta dos resultados da retrospecção dos dados do teste, desista do modelo e recomece. Não volte a re-otimizar o seu modelo, pois isso levará a um excesso de adequação! Também é recomendável criar um novo conjunto de dados do teste, pois este já está contaminado; no momento de desistir do modelo, já sabemos implicitamente o conteúdo do conjunto).

Aqui, nós vamos usar a caixa de ferramentas do 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)

img

Resultados do teste, Pnl calculado em dólares (Pnl não inclui custos de transação e outros custos)

Oitavo passo: Outras formas de melhorar o modelo

Verificação por rolagem, aprendizagem coletiva, Bagging e Boosting

Além de coletar mais dados, criar melhores características ou experimentar mais modelos, há algumas coisas que você pode tentar melhorar.

1. Verificação por rolagem

img

Verificação por rolagem

As condições do mercado raramente permanecem inalteradas. Suponha que você tenha dados de um ano e que você treine com dados de janeiro a agosto e use dados de setembro a dezembro para testar seu modelo, você pode acabar treinando para um conjunto de condições de mercado muito específicas. Talvez não haja flutuações no mercado no primeiro semestre, algumas notícias extremas levem o mercado a subir drasticamente em setembro, seu modelo não aprende esse padrão e lhe dá previsões de lixo.

Talvez seja melhor tentar a verificação por rolagem avançada, com treinamento de janeiro a fevereiro, treinamento de março, treinamento de abril a maio, treinamento de junho, etc.

2. Aprendizagem coletiva

img

Aprendizagem coletiva

Alguns modelos podem funcionar muito bem ao prever certos cenários, enquanto outros cenários ou em certas circunstâncias o modelo pode ser extremamente super-ajustado. Uma maneira de reduzir erros e super-ajustes é usar conjuntos de modelos diferentes. Sua previsão será a média das previsões feitas por muitos modelos, e os erros dos diferentes modelos podem ser compensados ou reduzidos. Alguns métodos comuns de agrupamento são Bagging e Boosting.

img

Embalagem

img

Reforço

Para uma breve introdução, vou ignorar esses métodos, mas você pode procurar mais informações online.

Vamos tentar uma abordagem de conjunto para o nosso problema.

basis_y_pred_ensemble = (basis_y_trees + basis_y_svr +
                         basis_y_knn + basis_y_regr)/4

img

Mean squared error: 0.02
Variance score: 0.95

Até agora, temos acumulado muito conhecimento e informação.

  • Resolva seus problemas

  • Coletar dados confiáveis e limpar dados

  • Dividir os dados em treinos, verificações e testes

  • Criar características e analisar seu comportamento

  • Escolha o modelo de treinamento adequado com base no comportamento

  • Use dados de treinamento para treinar o seu modelo e fazer previsões.

  • Verificar e re-otimizar o desempenho do conjunto de verificação

  • Verificar o desempenho final do conjunto de testes

Não é uma boa ideia? Mas ainda não acabou, agora você só tem um modelo de previsão confiável.

  • Desenvolver sinais baseados em modelos de previsão para identificar direções de negociação

  • Desenvolver estratégias específicas para identificar a liquidação

  • Sistema de execução para identificar posições e preços

A partir de agora, a plataforma de quantificação dos inventores será usada.FMZ.COMNo Inventor Quantification Platform, há muitas estratégias alternativas perfeitas, com o método de aprendizagem de máquina deste artigo, que irão fazer com que suas estratégias específicas sejam como as asas de um tigre.https://www.fmz.com/square

Notas importantes sobre os custos de transação:你的模型会告诉你所选资产何时是做多或做空。然而,它没有考虑费用/交易成本/可用交易量/止损等。交易成本通常会使有利可图的交易成为亏损。例如,预期价格上涨0.05美元的资产是买入,但如果你必须支付0.10美元进行此交易,你将最终获得净亏损$0.05。在你考虑经纪人佣金,交换费和点差后,我们上面看起来很棒的盈利图实际上是这样的:

img

Os resultados do retestamento após taxas de transação e desvio de pontos, Pnl em dólares

As taxas de transação e as diferenças representam mais de 90% do nosso PNL!

Para terminar, vamos ver algumas armadilhas comuns.

O que fazer e o que não

  • Não se encaixe demais com todos os esforços!

  • Não re-treine depois de cada ponto de dados: este é um erro comum cometido no desenvolvimento de aprendizado de máquina. Se o seu modelo precisa ser re-treinado após cada ponto de dados, então ele provavelmente não é um modelo muito bom. Ou seja, ele precisa ser re-treinado regularmente e apenas com uma frequência razoável (por exemplo, se for uma previsão diária, re-treine no final de cada semana)

  • Evite desvios, especialmente desvios prospectivos: esta é outra razão pela qual os modelos não funcionam, certifique-se de que você não usa qualquer informação futura. Na maioria das vezes, isso significa que não use a variável alvo Y como uma característica no modelo. Você pode usá-la durante o teste retrogrado, mas não será possível quando o modelo for efetivamente executado, o que deixará seu modelo inutilizável.

  • Alerta para o desvio de mineração de dados: como estamos tentando fazer uma série de modelagem de nossos dados para determinar se eles se encaixam, se não houver uma razão especial, certifique-se de executar testes rigorosos para separar os padrões aleatórios dos padrões reais que podem ocorrer. Por exemplo, a regressão linear explica bem os padrões de tendência ascendente, que provavelmente serão apenas uma fração de um grande fluxo aleatório!

Evitar a adaptação excessiva

O que é muito importante, e eu acho que é necessário relembrá-lo.

  • O excesso de adequação é a armadilha mais perigosa da estratégia de negociação.

  • Um algoritmo complexo pode ter um excelente desempenho em retrospectiva, mas falha em novos dados invisíveis, que não revelam realmente nenhuma tendência nos dados e não têm uma capacidade de previsão real.

  • Mantenha seu sistema o mais simples possível. Se você achar que precisa de muitas funções complexas para interpretar os dados, você pode estar se adaptando demais.

  • Divida seus dados disponíveis em dados de treinamento e teste e sempre verifique o desempenho dos dados reais da amostra antes de usar o modelo para transações em tempo real.


Relacionados

Mais.

A única coisa que eu seiObrigado, pai.

congcong009Excelentes artigos, ideias e resumos para iniciantes.

lalademaxiaQue arrogância!