Projeto de Data Science - Previsão de ações da bolsa de valores - Parte 3 - Finalizando o algoritmo
- Andressa Siqueira
- 2 de ago. de 2021
- 4 min de leitura
Atualizado: 24 de jul. de 2023
No post anterior verificamos a estacionaridade da nossa base, verificamos que o Valor-p é maior que 0.05 no teste de Dickey-Fuller, o que significa que a série não é estacionária.
Nosso trabalho agora é transformar a nossa série em estacionária, ou seja, a média, variância e estrutura de autocorrelação não mudam no decorrer do tempo.
Mas quais são os tipos de estacionaridade?
Existe 3 tipos de estacionaridade: a Estrita, de Tendência e Diferencial
Estacionaridade Estrita: é a série que satisfaz a definição matemática, ou seja, a média, variância e a covariância não são funções do tempo.
Estacionaridade de Tendência: é quando uma série, que ao se remover a tendência, o resultado é uma série estrita.
Estacionaridade Diferencial: é quando uma série, quando feita a diferenciação o resultado é uma série estrita
Para ter certeza de qual é o seu tipo de série é indicado sempre fazer os testes de KPSS (Kwiatkowski-Phillips-Schmidt-Shin) e o ADF (Augmented Dickey Fuller).
E quais são as principais razões que faz uma série temporal não ser estacionária?
Existe 2 motivos que fazem uma série temporal não ser estacionária:
Tendência - Média variável ao longo do tempo.
Sazonalidade - Variações em prazos específicos.
E se a série não for estacionária?
Podemos transformar com uma das técnicas abaixo [1]:
Transformações de potência - Aplicamos uma transformação matemática aos dados visando remover padrões e transformar a série em estacionária. As transformações de potência mais comuns são:
Transformação de log
Transformação exponencial
Transformação Box Cox
Transformação da raiz quadrada
Diferenciação - Podemos diferenciar os dados. Isto é, dada a série Yt, criamos a nova série: Y(i) = Y(i) - Y(i-1). Os dados diferenciados conterão um ponto a menos que os dados originais. Embora você possa diferenciar os dados mais que uma vez, uma diferenciação é geralmente suficiente.
Remoção de Tendência (Smoothing) - Se os dados tiverem uma tendência, podemos ajustar algum tipo de curva aos dados e depois então modelar os resíduos daquele ajuste. Desde que o propósito do ajuste é simplesmente remover tendências de longo prazo, um ajuste simples, tal como uma linha reta, é tipicamente usado. As transformações mais comuns são:
Média Móvel Simples
Média Móvel Ponderada Exponencial
Decomposição - Para dados negativos, você pode adicionar uma constante adequada para tornar todos os dados positivos antes de aplicar a transformação. Esta constante pode então ser subtraída do modelo para obter valores previstos (i.e., ajustados) e previsões para pontos futuros.
Nesse projeto vamos transformar usando a transformação de Log e a Média Móvel Simples. Depois faço artigos falando de cada método separadamente e faço outros projetos utilizando outras transformações.
Legal.... mas quais são os passos que devemos seguir!?
Calma pequeno gafanhoto! Vamos fazer o passo-a-passo juntos!
Vamos começar importando as seguintes bibliotecas:
import scipy
from scipy.stats import boxcox
Transformações de Log
Uma observação importante é que essa transformação assume que os valores são positivos e diferentes de zero.
dados_open['Open_log'] = np.log(dados_open['Open'])
dados_low['Low_log'] = np.log(dados_low['Low'])
dados_high['High_log'] = np.log(dados_high['High'])
dados_close['Close_log'] = np.log(dados_close['Close'])

Podemos perceber que a serie transformada, nesse caso, ficou com a mesma forma de antes. Mas agora que mudamos a escala dos dados vamos aplicar a....
Diferenciação
Para aplicar a diferenciação, basta seguir a seguinte fórmula:
dados_open['Open_log_diff'] = dados_open['Open_log'] - dados_open['Open_log'].shift(1)
Agora podemos gerar nossos gráficos para visualizamos o resultado:
dados_open['Open_log_diff'].dropna().plot(color = "blue")
dados_low['Low_log_diff'].dropna().plot(color = "blue")
dados_high['High_log_diff'].dropna().plot(color = "blue")
dados_close['Close_log_diff'].dropna().plot(color = "blue")

Podemos ver uma melhoria significativa no resultado se comparado com a nossa série inicial (Gráfico abaixo).

Para testar se a nossa série está estacionária ou não, basta refazer o teste de Dickey-Fuller.

Agora o nosso Valor-p teve tendência a 0! Esse é o melhor Valor-P que podemos encontrar após qualquer transformação! Com isso vemos que não existe a necessidade de realizar nenhum teste com outro tipo de transformação.
Se tivéssemos encontrado um Valor-p diferente de 0, seria válido testarmos outros tipos de transformações.
E como eu faço a previsão depois dessa transformação!?
Calma pequeno pawdwan....
Primeiramente vamos tentar através do método Naive (ingênuo). Nesse método dados reais do último período são usados como previsão desse período, sem ajustá-los ou tentar estabelecer fatores causais.
Aqui vou colocar apenas o código referente aos dados dos valores de abertura da bolsa, mas no github tem o código completo para todos os valores ( abertura, alta, baixa e fechamento)
Para isso, primeiramente separamos nossos dados em treino e validação através da função iloc e depois criamos um array com os valores de variável do treino
#separamos o dados para treino e validacao
dados_open_treino = dados_open_na.iloc[0:4325]
dados_open_valid = dados_open_na.iloc[4326:]
# Criamos um array com os valores da variável target em treino
array_target_treino = np.asarray(dados_open_treino.Open_log_diff)
array_target_treino
Em seguida, associamos os valores do array a nossa base
Cria uma cópia dos dados de validação
dados_open_valid_copy = dados_open_na.copy()
dados_open_valid_copy['previsao']= array_target_treino[len(array_target_treino) - 1]
dados_open_valid_copy[['Open_log_diff', 'previsao']].head()
Agora vamos plotar nossa base para vermos como ficou
# Plot
plt.title("Previsão Usando Método Naive")
plt.plot(dados_open_treino.index, dados_open_treino['Open_log_diff'], label = 'Dados de Treino')
plt.plot(dados_open_valid.index, dados_open_valid['Open_log_diff'], label = 'Dados de Validação')
plt.plot(dados_open_valid_copy.index, dados_open_valid_copy['previsao'], label = 'Naive Forecast')
plt.legend(loc = 'best')
plt.show()

Para sabermos se a nossa função tem uma boa previsão, vamos calcular o desvio médio quadrático.
# Define valor real e valor previsto
y_true = dados_open_valid_copy.Open_log_diff
y_pred = dados_open_valid_copy.previsao
# Calcula o erro usando RMSE (Root Mean Squared Error)
metrica_rmse = sqrt(mean_squared_error(y_true, y_pred))
print(metrica_rmse)
No caso, para esse método tivemos o erro de 0.05241995613242522 que é extremamente baixo mostrando que temos um bom algoritmo.
Conclusão:
Apesar do algoritmo ter um erro bem baixo, ele não é tão assertivo, pois nesse casos existe várias variáveis subjetivas que não tem como ser incorporadas nas fórmulas tais como incertezas do mercado, mudança de governo entre outras coisas. Essas incertezas e mudanças podem causar uma retração no mercado, fazendo com que os valores de determinadas ações caiam ou trazer mais confiança fazendo o valor subir.
Referências:
[1] Aula do data science academy
Comments