
Estratégia de Negociação do SP500 em MQL5 para Iniciantes
Introdução
Este artigo discutirá como podemos construir uma estratégia de negociação inteligente para negociar o Índice Standard & Poor’s 500 (S&P 500) usando MQL5. Nossa discussão mostrará como aproveitar a flexibilidade do MQL5 para construir um Expert Advisor dinâmico que dependa de uma combinação de Inteligência Artificial e análise técnica. Nosso raciocínio é que depender exclusivamente da IA pode levar a estratégias instáveis; no entanto, ao guiar a IA com os princípios testados da análise técnica, podemos alcançar uma abordagem mais confiável. Essa estratégia híbrida visa descobrir padrões ocultos dentro das grandes quantidades de dados disponíveis em nossos terminais MetaTrader 5, aproveitando as forças tanto da IA quanto da análise tradicional e da linguagem MQL5 para melhorar o desempenho de negociação e a tomada de decisões.
Após ler este artigo, você ganhará:
- Bons princípios de programação para MQL5
- Insights sobre como os traders podem facilmente analisar grandes conjuntos de dados de múltiplos símbolos simultaneamente usando comandos de álgebra linear na API MQL5.
- Técnicas para descobrir padrões ocultos nos dados do mercado que não são imediatamente aparentes.
História: O Que é o Standard & Poor's 500?
O S&P 500, introduzido em 1957, é um benchmark crucial que reflete o desempenho geral da economia dos EUA. Ao longo dos anos, várias empresas foram adicionadas e removidas do índice, refletindo a natureza dinâmica do mercado. Entre os membros de longa data, General Electric, J.P. Morgan e Goldman Sachs mantiveram suas posições no índice desde sua criação.
O S&P 500 representa o valor médio das 500 maiores empresas dos Estados Unidos da América. O S&P 500 representa o valor médio das 500 maiores empresas dos Estados Unidos da América. Portanto, o S&P 500 também pode ser considerado como um índice ponderado pela capitalização de mercado das 500 maiores empresas de capital aberto do mundo.
Hoje em dia, empresas inovadoras como Tesla e Nvidia redefiniram o benchmark desde sua fundação. O S&P 500 agora vê a maior parte de seu peso concentrado em grandes empresas de tecnologia, incluindo Google, Apple e Microsoft, entre os gigantes mencionados. Esses titãs da tecnologia transformaram o cenário do índice, refletindo a mudança na economia em direção à tecnologia e inovação.
Visão Geral de Nossa Estratégia de Negociação
Uma lista das empresas incluídas no índice é facilmente acessível na internet. Podemos aproveitar nosso entendimento sobre como o índice é composto para nos ajudar a criar uma estratégia de negociação. Selecionaremos algumas das maiores empresas do índice e usaremos o preço respectivo de cada empresa como entrada para um modelo de IA que preverá o preço de fechamento do índice com base em nossa amostra de empresas que detêm grandes pesos proporcionais. Nosso desejo é desenvolver uma estratégia que combine IA com técnicas comprovadas e confiáveis.
Nosso sistema de análise técnica utilizará princípios de acompanhamento de tendências para gerar sinais de negociação. Precisamos incorporar vários indicadores chave:
- O Commodity Channel Index (CCI) como nosso indicador de volume. Queremos entrar apenas em negociações que sejam apoiadas por volume.
- O Relative Strength Index (RSI) e o Williams Percent Range (WPR) para medir a pressão de compra ou venda no mercado.
- Uma Moving Average (MA) como nosso indicador de confirmação final.
O Commodity Channel Index (CCI) gira em torno de 0. Uma leitura acima de 0 sugere um volume forte para uma oportunidade de compra, enquanto uma leitura abaixo de 0 indica um volume de apoio para venda. Precisamos de alinhamento com outros indicadores para confirmação de negociação, melhorando nossas chances de encontrar configurações de alta probabilidade.
Portanto, para que possamos comprar:
- A leitura do CCI deve ser maior que 0.
- A leitura do RSI deve ser maior que 50.
- A leitura do WPR deve ser maior que -50.
- A MA deve estar abaixo do preço de fechamento.
E, inversamente, para vender:
- A leitura do CCI deve ser menor que 0.
- A leitura do RSI deve ser menor que 50.
- A leitura do WPR deve ser menor que -50.
- A MA deve estar acima do preço de fechamento.
Por outro lado, para construir nosso sistema de IA, precisamos primeiro buscar os preços históricos de 12 ações de grande capitalização incluídas no S&P 500 e os preços de fechamento do S&P 500. Esses serão nossos dados de treinamento que usaremos para construir nosso modelo de regressão linear múltipla para prever os preços futuros do índice.
A partir daí, o sistema de IA utilizará a regressão dos mínimos quadrados ordinários para prever o valor de fechamento do S&P 500.
Fig 1: Nosso modelo verá o S&P500 como a saída de uma coleção dessas ações.
Uma vez que tivermos os dados prontos, podemos estimar os parâmetros do modelo para nossa regressão linear usando a seguinte fórmula.
Fig 2: A equação acima demonstra uma das várias maneiras de estimar os parâmetros de um modelo de regressão linear múltipla.
A expressão "Ax - y" cercada por duas linhas verticais é conhecida como o norm L2 de um vetor, pronunciado "ell 2". Na linguagem cotidiana, quando perguntamos "qual o tamanho?", sobre objetos físicos, falamos sobre seu tamanho ou magnitude. Da mesma forma, quando perguntamos "qual o tamanho" de um vetor, nos referimos ao seu norm. Um vetor é essencialmente uma lista de números. Embora existam diferentes tipos de normas, as normas L1 e L2 são as mais comuns. Hoje, vamos focar na norm L2, que é calculada como a raiz quadrada da soma dos valores ao quadrado dentro do vetor.
Neste contexto:
- A matriz "A" representa os dados de entrada, consistindo dos valores de fechamento de 12 ações diferentes.
- O símbolo "x" denota os valores dos coeficientes para nosso modelo de regressão linear múltipla, com um coeficiente por ação.
- O produto "Ax" representa nossas previsões para o futuro preço do índice S&P 500 com base em nossos dados de treinamento.
- A notação "y" simboliza o vetor dos preços reais de fechamento que tentamos prever durante o treinamento.
Essencialmente, a primeira equação nos diz que estamos procurando valores de "x" que minimizem o norm L2 de "Ax - y". Em outras palavras, estamos buscando os valores de "x" que minimizam nosso erro de previsão ao prever o preço de fechamento do S&P 500.
A segunda equação revela que os valores de "x" que atingem o erro mínimo podem ser encontrados multiplicando a pseudo-inversa de "A" pelos dados de saída (y) de nosso conjunto de treinamento. A operação de pseudo-inversa é convenientemente implementada no MQL5.
Podemos encontrar eficientemente a solução pseudo-inversa em MQL5 com apenas algumas linhas de código.
Implementação: Estratégia de Negociação SP500
Começando
Primeiro, precisamos definir os parâmetros para nosso Expert Advisor. Precisamos de parâmetros para permitir que o usuário altere os períodos de nossos indicadores técnicos.
//+------------------------------------------------------------------+ //| SP500 Strategy EA.mq5 | //| Copyright 2024, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Gamuchirai Zororo Ndawana" #property link "https://www.mql5.com" #property version "1.00" /* O objetivo desta aplicação é implementar uma estratégia para negociar o SP500 com base no desempenho de uma amostra de ações que detêm pesos proporcionalmente grandes no índice e na análise técnica clássica. Usaremos as seguintes ações: 1)Microsoft 2)Apple 3)Google 4)Meta 5)Visa 6)JPMorgan 7)Nvidia 8)Tesla 9)Johnsons N Johnsons 10)Home Depot 11)Proctor & Gamble 12)Master Card Uma estratégia que dependa exclusivamente da IA pode se mostrar instável. Queremos usar uma combinação de IA guiada por estratégias de negociação que foram confiáveis ao longo do tempo. Nossa IA será um sistema linear mapeando o preço de cada ação para o preço de fechamento do índice. Lembre-se de que os dados de séries temporais financeiras podem ser muito ruidosos. Usar modelos mais simples pode ser benéfico. Tentaremos encontrar coeficientes lineares usando os mínimos quadrados ordinários. Usaremos a solução da pseudo-inversa para encontrar os parâmetros do nosso modelo. Nossa análise técnica será baseada em princípios de acompanhamento de tendências: 1.Devemos observar um aumento de volume que suporte a negociação antes de entrarmos. 2. Queremos 2 indicadores de confirmação, RSI e WPR, confirmando a tendência. 3. Queremos que o preço ultrapasse o máximo ou mínimo da semana anterior. 4. Queremos que o preço esteja acima ou abaixo de nossa MA antes de negociar. Nosso objetivo é encontrar uma combinação ótima de insight estatístico e análise técnica clássica para, com sorte, construir uma estratégia com vantagem. Gamuchirai Zororo Ndawana Selebi Phikwe Botswana Monday 8 July 2024 21:03 */ //Inputs //How far ahead into the future should we forecast? input int look_ahead = 10; //Our moving average period input int ma_period = 120; //Our RSI period input int rsi_period = 10; //Our WPR period input int wpr_period = 30; //Our CCI period input int cci_period = 40; //How big should our lot sizes be? int input lot_multiple = 20;
A seguir, precisamos importar nossa biblioteca de negociações para que possamos gerenciar nossas posições.
//Libraries //Trade class #include <Trade/Trade.mqh> CTrade Trade;
Avançando, precisamos definir variáveis globais que serão usadas em todo o nosso programa.
//Global variables //Smallest lot size double minimum_volume; //Ask double ask_price; //Bid double bid_price; //How much data should we fetch? int fetch = 20; //Determine the starting date for our inputs int inupt_start; //Determine the starting date for our outputs int output_start; //Which symbols are we going to use to forecast the SP500 close? string desired_symbols[] = {"MSFT","AAPL","NVDA","GOOG","TSLA","META","JPM","JNJ","V","PG","HD","MA"}; //Define our input matrix matrix input_matrix = matrix::Ones(fetch,(ArraySize(desired_symbols))-1); //Define our output matrix, our output matrix has one column matrix output_matrix = matrix::Ones(fetch,1); //A vector to store the initial values of each column vector initiall_input_values = vector::Ones((ArraySize(desired_symbols))); //A variable to store the initial value of the output double initiall_output_value = 0.0; //Defining the matrix that will store our model parameters matrix b; //Define our target symbol string target_symbol = "US_500"; //A vector to temporarily store the historic closing price of each stock vector symbol_history = vector::Zeros(fetch); //A flag to let us know when our model is ready bool model_initialized = false; //A flag to let us know if the training process has started bool model_being_trained = false; //Our model's prediction double model_forecast = 0; //Handlers for our technical indicators int cci_handler,rsi_handler,wpr_handler,ma_handler; //Buffers for our technical indicator values double cci_buffer[],rsi_buffer[],wpr_buffer[],ma_buffer[];
Agora que chegamos até aqui, devemos configurar nossos indicadores técnicos no manipulador de inicialização.
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- //Let's setup our technical indicators rsi_handler = iRSI(target_symbol,PERIOD_CURRENT,rsi_period,PRICE_CLOSE); ma_handler = iMA(target_symbol,PERIOD_CURRENT,ma_period,0,MODE_EMA,PRICE_CLOSE); wpr_handler = iWPR(target_symbol,PERIOD_CURRENT,wpr_period); cci_handler = iCCI(target_symbol,PERIOD_CURRENT,cci_period,PRICE_CLOSE); //Get market data minimum_volume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); //--- return(INIT_SUCCEEDED); }
Precisamos de funções auxiliares. Inicialmente, definimos um procedimento para inicializar nosso modelo de regressão linear múltipla. Nosso procedimento de ajuste começa definindo uma flag para indicar que nosso modelo está em treinamento. Funções adicionais lidam com tarefas como recuperar dados de treinamento e ajustar o modelo. Ao dividir nosso código em funções menores, evitamos escrever as mesmas linhas de código várias vezes.
//+------------------------------------------------------------------+ //This function defines the procedure for fitting our model void model_initialize(void) { /* Our function will run the initialization procedure as follows: 1)Update the training flag to show that the model has been trained 2)Fetch the necessary input and output data 3)Preprocess the data, normalization and scaling etc. 4)Fit the model 5)Update the flags to show that the model has been trained. A partir daí, nosso aplicativo poderá começar a negociar. */ //First let us set our flag to denote that the model is being trained model_being_trained = true; //Defining the input start time and the output start time //Remember the input data should not contain the most recent bars //The most recent bars must only be included in the output start time //The input data should be older than the output data. inupt_start = 1+look_ahead; output_start = 1; //Fetch the input data fetch_input_data(inupt_start,fetch); //Fetch the output data fetch_output_data(output_start,fetch); //Prepare the data prepare_data(0); //Fit our model fit_linear_model(); //The model is ready model_ready(); }
Agora, prosseguimos para definir a função responsável por buscar nossos dados de entrada. Nossa matriz de entrada incluirá uma coluna de uns na primeira coluna para representar o ponto de interceptação ou o preço médio de fechamento do S&P 500 quando todos os valores das ações forem zero. Embora esse cenário não faça sentido no mundo financeiro, pois, se todos os valores das ações fossem 0, o preço de fechamento do S&P 500 também seria 0.
De qualquer forma, nosso procedimento para buscar os dados de entrada é simples:
- Inicialize a matriz de entrada cheia de uns.
- Redimensione a matriz.
- Preencha o valor de fechamento de cada ação, começando pela segunda coluna.
- Certifique-se de que a primeira coluna esteja cheia de uns.
//This function will get our input data ready void fetch_input_data(int f_input_start,int f_fetch) { /* Para preparar os dados de entrada, percorreremos os símbolos disponíveis e copiaremos a quantidade de dados solicitada para a matriz de entrada com escopo global. Nossos parâmetros de função são: 1. f_input_start: é aqui que devemos obter nossos dados de entrada, para os dados atuais passe 0 e busque apenas 1. 2. f_fetch: é a quantidade de dados que deve ser buscada e copiada para a matriz de entrada. */ Print("Preparing to fetch input data"); //Let's observe the original state of our input matrix Print("We will reset the input matrix before fetching the data we need: "); input_matrix = matrix::Ones(f_fetch,(ArraySize(desired_symbols))-1); Print(input_matrix); //We need to reshape our matrix input_matrix.Reshape(f_fetch,13); //Filling the input matrix //Then we need to prepare our input matrix. //The first column must be full of 1's because it represents the intercept. //Therefore we will skip 0, and start filling input values from column 1. This is not a mistake. for(int i=1; i <= ArraySize(desired_symbols);i++) { //Copy the input data we need symbol_history.CopyRates(desired_symbols[i-1],PERIOD_CURRENT,COPY_RATES_CLOSE,f_input_start,f_fetch); //Insert the input data into our input matrix input_matrix.Col(symbol_history,i); } //Ensure that the first column is full of ones for our intercept vector intercept = vector::Ones(f_fetch); input_matrix.Col(intercept,0); //Let us see what our input matrix looks like now. Print("Final state of our input matrix: "); Print(input_matrix); }Nosso procedimento para buscar os dados de saída será mais ou menos o mesmo que fizemos para buscar os dados de entrada.
//This function will get our output data ready void fetch_output_data(int f_output_start, int f_fetch) { /* This function will fetch our output data for training our model and copy it into our globally defined output matrix. The model has only 2 parameters: 1)f_output_start: where should we start copying our output data 2)f_fetch: amount of data to copy */ Print("Preparing to fetch output data"); //Let's observe the original state of our output matrix Print("Ressetting output matrix before fetching the data we need: "); //Reset the output matrix output_matrix = matrix::Ones(f_fetch,1); Print(output_matrix); //We need to reshape our matrix output_matrix.Reshape(f_fetch,1); //Output data //Copy the output data we need symbol_history.CopyRates(target_symbol,PERIOD_CURRENT,COPY_RATES_CLOSE,f_output_start,f_fetch); //Insert the output data into our input matrix output_matrix.Col(symbol_history,0); //Let us see what our input matrix looks like now. Print("Final state of our output matrix: "); Print(output_matrix); }
Antes de ajustar nosso modelo, precisamos padronizar e escalar nossos dados. Esta é uma etapa importante porque facilita o aprendizado das relações ocultas nas taxas de mudança para nossa aplicação.
Observe que nosso procedimento de ajuste tem 2 fases distintas: na fase 1, quando o modelo está sendo treinado pela primeira vez, precisamos armazenar os valores que usamos para escalar cada coluna em um vetor. Cada coluna será dividida pelo primeiro valor nela, o que significa que o primeiro valor em cada coluna será um.
A partir daí, se observarmos qualquer valor menor que um nessa coluna, significa que o preço caiu, e valores maiores que um indicam que o preço aumentou. Se observarmos uma leitura de 0,72, significa que o preço caiu 28% e, se observarmos um valor de 1,017, significa que o preço aumentou 1,7%.
Devemos armazenar apenas o valor inicial de cada coluna uma vez; a partir daí, todos os futuros dados de entrada devem ser divididos pela mesma quantidade para garantir consistência.
//This function will normalize our input data so that our model can learn better //We will also scale our output so that it shows the growth in price void prepare_data(int f_flag) { /* This function is responsible for normalizing our inputs and outputs. Queremos primeiro armazenar o valor inicial de cada coluna. Em seguida, vamos dividir cada coluna pelo seu primeiro valor, para que o primeiro valor em cada coluna seja um. As etapas acima são realizadas apenas uma vez, quando o modelo é inicializado. Todos os dados de entrada subsequentes serão simplesmente divididos pelos valores iniciais dessa coluna. */ Print("Normalizing and scaling the data"); //This part of the procedure should only be performed once if(f_flag == 0) { Print("Preparing to normalize the data for training the model"); //Normalizing the inputs //Store the initial value of each column for(int i=0;i<ArraySize(desired_symbols);i++) { //First we store the initial value of each column initiall_input_values[i] = input_matrix[0][i+1]; //Now temporarily copy the column, so that we can normalize the entire column at once vector temp_vector = input_matrix.Col(i+1); //Now divide that entire column by its initial value, if done correctly the first value of each column should be 1 temp_vector = temp_vector / initiall_input_values[i]; //Now reinsert the normalized column input_matrix.Col(temp_vector,i+1); } //Print the initial input values Print("Our initial input values for each column "); Print(initiall_input_values); //Scale the output //Store the initial output value initiall_output_value = output_matrix[0][0]; //Make a temporary copy of the entire output column vector temp_vector_output = output_matrix.Col(0); //Divide the entire column by its initial value, so that the first value in the column is one //This means that any time the value is less than 1, price fell //And every time the value is greater than 1, price rose. //A value of 1.023... means price increased by 2.3% //A value of 0.8732.. would mean price fell by 22.67% temp_vector_output = temp_vector_output / initiall_output_value; //Reinsert the column back into the output matrix output_matrix.Col(temp_vector_output,0); //Shpw the scaled data Print("Data has been normlised and the output has been scaled:"); Print("Input matrix: "); Print(input_matrix); Print("Output matrix: "); Print(output_matrix); } //Normalize the data using the initial values we have allready calculated if(f_flag == 1) { //Divide each of the input values by its corresponding input value Print("Preparing to normalize the data for prediction"); for(int i = 0; i < ArraySize(desired_symbols);i++) { input_matrix[0][i+1] = input_matrix[0][i+1]/initiall_input_values[i]; } Print("Input data being used for prediction"); Print(input_matrix); } }
Agora, precisamos definir uma função que definirá as condições necessárias para permitir que nossa aplicação comece a negociar.
//This function will allow our program to switch states and begin forecasting and looking for trades void model_ready(void) { //Our model is ready. //We need to switch these flags to give the system access to trading functionality Print("Giving the system permission to begin trading"); model_initialized = true; model_being_trained = false; }
Para obter uma previsão do nosso Expert Advisor, devemos primeiro buscar os dados mais recentes disponíveis, pré-processar os dados e então usar a equação de regressão linear para obter uma previsão do nosso modelo.
//This function will obtain a prediction from our model double model_predict(void) { //First we have to fetch current market data Print("Obtaining a forecast from our model"); fetch_input_data(0,1); //Now we need to normalize our data using the values we calculated when we initialized the model prepare_data(1); //Now we can return our model's forecast return((b[0][0] + (b[1][0]*input_matrix[0][0]) + (b[2][0]*input_matrix[0][1]) + (b[3][0]*input_matrix[0][2]) + (b[4][0]*input_matrix[0][3]) + (b[5][0]*input_matrix[0][4]) + (b[6][0]*input_matrix[0][5]) + (b[7][0]*input_matrix[0][6]) + (b[8][0]*input_matrix[0][7]) + (b[9][0]*input_matrix[0][8]) + (b[10][0]*input_matrix[0][9]) + (b[11][0]*input_matrix[0][10])+ (b[12][0]*input_matrix[0][11]))); }
Precisamos implementar um procedimento para ajustar nosso modelo linear usando as equações que definimos e explicamos acima. Observe que nossa API MQL5 nos oferece a flexibilidade para executar nossos comandos de álgebra linear de forma flexível e fácil de usar, podemos facilmente encadear operações, tornando nossos produtos altamente performáticos.
Isso é especialmente importante se você deseja vender seus produtos no mercado; evite usar loops "for" sempre que pudermos realizar operações vetoriais, pois as operações vetoriais são mais rápidas que loops. Seus usuários finais terão uma aplicação muito responsiva, sem atrasos, e irão aproveitar a experiência do usuário.
//This function will fit our linear model using the pseudo inverse solution void fit_linear_model(void) { /* The pseudo inverse solution finds a list of values that maps our training data inputs to the output by minimizing the error, RSS. Esses valores de coeficientes podem ser facilmente estimados usando álgebra linear, no entanto, esses coeficientes minimizam nosso erro nos dados de treinamento e também em dados não vistos! */ Print("Attempting to find OLS solutions."); //Now we can estimate our model parameters b = input_matrix.PInv().MatMul(output_matrix); //Let's see our model parameters Print("Our model parameters "); Print(b); }
Avançando, precisamos de uma função responsável por atualizar nossos indicadores técnicos e buscar os dados atuais do mercado.
//Update our technical indicator values void update_technical_indicators() { //Get market data ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK); bid_price = SymbolInfoDouble(_Symbol,SYMBOL_BID); //Copy indicator buffers CopyBuffer(rsi_handler,0,0,10,rsi_buffer); CopyBuffer(cci_handler,0,0,10,cci_buffer); CopyBuffer(wpr_handler,0,0,10,wpr_buffer); CopyBuffer(ma_handler,0,0,10,ma_buffer); //Set the arrays as series ArraySetAsSeries(rsi_buffer,true); ArraySetAsSeries(cci_buffer,true); ArraySetAsSeries(wpr_buffer,true); ArraySetAsSeries(ma_buffer,true); }
Em seguida, escreveremos uma função que executará nossas configurações de negociação. Nossa função só poderá executar negociações se ambos os nossos sistemas estiverem alinhados.
//Let's try find an entry signal void find_entry(void) { //Our sell setup if(bearish_sentiment()) { Trade.Sell(minimum_volume * lot_multiple,_Symbol,bid_price); } //Our buy setup else if(bullish_sentiment()) { Trade.Buy(minimum_volume * lot_multiple,_Symbol,ask_price); } }
Isso é possível porque temos funções que definem o sentimento de baixa de acordo com as descrições acima.
//This function tells us if all our tools align for a sell setup bool bearish_sentiment(void) { /* For a sell setup, we want the following conditions to be satisfied: 1) CCI reading should be less than 0 2) RSI reading should be less than 50 3) WPR reading should be less than -50 4) Our model forecast should be less than 1 5) MA reading should be below the moving average */ return((iClose(target_symbol,PERIOD_CURRENT,0) < ma_buffer[0]) && (cci_buffer[0] < 0) && (rsi_buffer[0] < 50) && (wpr_buffer[0] < -50) && (model_forecast < 1)); }
E o mesmo é válido para nossa função que define o sentimento de alta.
//This function tells us if all our tools align for a buy setup bool bullish_sentiment(void) { /* For a sell setup, we want the following conditions to be satisfied: 1) CCI reading should be greater than 0 2) RSI reading should be greater than 50 3) WPR reading should be greater than -50 4) Our model forecast should be greater than 1 5) MA reading should be above the moving average */ return((iClose(target_symbol,PERIOD_CURRENT,0) > ma_buffer[0]) && (cci_buffer[0] > 0) && (rsi_buffer[0] > 50) && (wpr_buffer[0] > -50) && (model_forecast > 1)); }
Por fim, precisamos de uma função auxiliar para atualizar nossos valores de stop loss e take profit.
//+----------------------------------------------------------------------+ //|This function is responsible for calculating our SL & TP values | //+----------------------------------------------------------------------+ void update_stoploss(void) { //First we iterate over the total number of open positions for(int i = PositionsTotal() -1; i >= 0; i--) { //Then we fetch the name of the symbol of the open position string symbol = PositionGetSymbol(i); //Before going any furhter we need to ensure that the symbol of the position matches the symbol we're trading if(_Symbol == symbol) { //Now we get information about the position ulong ticket = PositionGetInteger(POSITION_TICKET); //Position Ticket double position_price = PositionGetDouble(POSITION_PRICE_OPEN); //Position Open Price long type = PositionGetInteger(POSITION_TYPE); //Position Type double current_stop_loss = PositionGetDouble(POSITION_SL); //Current Stop loss value //If the position is a buy if(type == POSITION_TYPE_BUY) { //The new stop loss value is just the ask price minus the ATR stop we calculated above double atr_stop_loss = NormalizeDouble(ask_price - ((min_distance * sl_width)/2),_Digits); //The new take profit is just the ask price plus the ATR stop we calculated above double atr_take_profit = NormalizeDouble(ask_price + (min_distance * sl_width),_Digits); //If our current stop loss is less than our calculated ATR stop loss //Or if our current stop loss is 0 then we will modify the stop loss and take profit if((current_stop_loss < atr_stop_loss) || (current_stop_loss == 0)) { Trade.PositionModify(ticket,atr_stop_loss,atr_take_profit); } } //If the position is a sell else if(type == POSITION_TYPE_SELL) { //The new stop loss value is just the ask price minus the ATR stop we calculated above double atr_stop_loss = NormalizeDouble(bid_price + ((min_distance * sl_width)/2),_Digits); //The new take profit is just the ask price plus the ATR stop we calculated above double atr_take_profit = NormalizeDouble(bid_price - (min_distance * sl_width),_Digits); //If our current stop loss is greater than our calculated ATR stop loss //Or if our current stop loss is 0 then we will modify the stop loss and take profit if((current_stop_loss > atr_stop_loss) || (current_stop_loss == 0)) { Trade.PositionModify(ticket,atr_stop_loss,atr_take_profit); } } } }
Todas as nossas funções auxiliares serão chamadas no momento apropriado pelo nosso manipulador OnTick, que é responsável por controlar o fluxo de eventos dentro de nosso terminal sempre que o preço mudar.
void OnTick() { //Our model must be initialized before we can begin trading. switch(model_initialized) { //Our model is ready case(true): //Update the technical indicator values update_technical_indicators(); //If we have no open positions, let's make a forecast using our model if(PositionsTotal() == 0) { //Let's obtain a prediction from our model model_forecast = model_predict(); //Now that we have sentiment from our model let's try find an entry find_entry(); Comment("Model forecast: ",model_forecast); } //If we have an open position, we need to manage it if(PositionsTotal() > 0) { //Update our stop loss update_stoploss(); } break; //Default case //Our model is not yet ready. default: //If our model is not being trained, train it. if(!model_being_trained) { Print("Our model is not ready. Starting the training procedure"); model_initialize(); } break; } }
Fig 3: Nossa aplicação em ação.
Limitações
Há algumas limitações em relação à abordagem de modelagem que escolhemos para nossos modelos de IA, vamos destacar algumas das mais importantes:
1.1 Entradas Correlacionadas
Os problemas causados por entradas correlacionadas não são exclusivos de modelos lineares, esse problema afeta muitos modelos de Machine Learning. Algumas das ações que temos em nossa matriz de entrada operam na mesma indústria e seus preços tendem a subir e descer ao mesmo tempo, isso pode dificultar para o nosso modelo isolar o efeito que cada ação tem no desempenho do índice, pois os movimentos de preços das ações podem estar se mascarando mutuamente.
1.2 Função Objetivo Não Linear
Conjuntos de dados financeiros que são inherentemente ruidosos geralmente são mais adequados para modelos mais simples, como a regressão linear múltipla. No entanto, na maioria dos casos da vida real, as funções reais que estão sendo aproximadas raramente são lineares. Portanto, quanto mais distante da linearidade a função verdadeira for, mais variância será observada na precisão do modelo.
1.3 Limitações de uma Abordagem de Modelagem Direta
Por fim, se fôssemos incluir todas as ações listadas no S&P 500 em nosso modelo, acabaríamos com um modelo contendo 500 parâmetros. Otimizar tal modelo exigiria recursos computacionais significativos e interpretar seus resultados apresentaria desafios. Soluções de modelagem direta não escalonam bem neste contexto; à medida que adicionamos mais ações no futuro, o número de parâmetros a otimizar pode rapidamente se tornar difícil de gerenciar.
Conclusão
Neste artigo, demonstramos como é simples começar a construir modelos de IA que integrem análise técnica para decisões de negociação informadas. À medida que avançamos para modelos mais avançados, a maioria das etapas abordadas hoje permanecerá inalterada. Isso deve dar confiança aos iniciantes, sabendo que completaram um projeto de machine learning do início ao fim e, esperamos, entenderam a lógica por trás de cada decisão.
Toda a nossa aplicação utiliza código nativo MQL5 e aproveita os indicadores técnicos padrão disponíveis em cada instalação do MetaTrader 5. Esperamos que este artigo inspire você a explorar mais possibilidades com suas ferramentas existentes e continue avançando no domínio do MQL5.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/14815
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Esse artigo foi escrito por um usuário do site e reflete seu ponto de vista pessoal. A MetaQuotes Ltd. não se responsabiliza pela precisão das informações apresentadas nem pelas possíveis consequências decorrentes do uso das soluções, estratégias ou recomendações descritas.





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
Muito obrigado por seu código interessante e bem documentado. Estou ansioso para fazê-lo funcionar. Há pelo menos uma armadilha para os novatos, que é alterar o símbolo de destino na linha 92 para o símbolo de sua corretora para sp500, e também na linha 84 para corresponder aos símbolos de ações de sua corretora.
O que a linha 286 'Our Model Parameters' deve retornar? Recebo [-nan(ind)], mas o restante parece funcionar perfeitamente.
Muito obrigado por seu código interessante e bem documentado. Estou ansioso para fazê-lo funcionar. Há pelo menos uma armadilha para os novatos, que é alterar o símbolo de destino na linha 92 para o símbolo de sua corretora para sp500, e também na linha 84 para corresponder aos símbolos de ações de sua corretora.
O que a linha 286 'Our Model Parameters' deve retornar? Recebo [-nan(ind)], mas o restante parece funcionar perfeitamente.
Eu tinha esperança de que isso realmente funcionasse. Agradeço ao autor por compartilhá-lo.
não é possível carregar o indicador'Relative Strength Index' [4302]
não é possível carregar o indicador 'Moving Average' [4302]
não é possível carregar o indicador 'Williams' Percent Range' [4302]
não é possível carregar o indicador 'Commodity Channel Index' [4302]
Entendo que os indicadores devem ser carregados e exibidos automaticamente (falha).
Coloquei manualmente os indicadores no gráfico e até criei um modelo com todos os indicadores incluídos. Mesmo quando o gráfico de todas as ações está aberto e todos os indicadores são colocados manualmente no gráfico, o EA não consegue ler os indicadores por conta própria.
não é possível carregar o indicador 'Moving Average' [4302]
não é possível carregar o indicador 'Williams' Percent Range' [4302]
não é possível carregar o indicador 'Commodity Channel Index' [4302]
Entendo que os indicadores devem ser carregados e exibidos automaticamente (falha).
Coloquei manualmente os indicadores no gráfico e até criei um modelo com todos os indicadores incluídos. Mesmo quando o gráfico de todas as ações está aberto e todos os indicadores são colocados manualmente no gráfico, o EA não consegue ler os indicadores por conta própria.