
Construa Consultores Especialistas Autossustentáveis com MQL5 e Python
Sinopse
Desenvolvedores de negociação algorítmica enfrentam o grande desafio de se adaptar às condições de mercado que estão em constante evolução, as quais mudam de forma imprevisível ao longo do tempo. À medida que essas condições mudam, também devem mudar as estratégias empregadas. Por exemplo, uma estratégia de reversão à média pode ser ideal quando os mercados exibem um comportamento de faixa restrita. No entanto, quando os mercados começam a se mover consistentemente em uma direção, uma estratégia de seguimento de tendência se torna mais adequada.
Frequentemente, como desenvolvedores, implementamos uma única estratégia de negociação e tentamos aplicá-la universalmente a todas as condições de mercado. Infelizmente, essa abordagem não pode garantir sucesso consistente. Alternativamente, também é possível programar várias estratégias de negociação em um único programa, permitindo que o usuário final selecione manualmente a estratégia mais apropriada, usando seu critério.
Portanto, é evidente que precisamos projetar programas capazes de selecionar e alternar autonomamente entre diferentes estratégias com base nas condições prevalentes do mercado. Para alcançar isso, precisamos de um método quantitativo para medir a força das tendências ou dos movimentos de reversão à média no mercado. Assim que nosso Consultor Especialista avaliar a força de cada movimento, ele poderá escolher a estratégia ideal a seguir.
Este artigo demonstra como podemos alcançar nosso objetivo de forma inteligente, utilizando uma matriz de transição para modelar o comportamento do mercado e determinar se devemos empregar estratégias de seguimento de tendência ou de reversão à média. Começamos desenvolvendo uma compreensão geral das matrizes de transição. Em seguida, exploramos como essas ferramentas matemáticas podem ser usadas para criar algoritmos de negociação inteligentes com habilidades aprimoradas de tomada de decisão.
Introdução: Quem Foi Andrey Markov?
Fig 1: Uma foto de um jovem Andrey Markov.
Fig 2: Um modelo fictício de Markov de uma empresa de transporte e as rotas usadas aleatoriamente por seus clientes.
Vamos interpretar a Cadeia de Markov acima. Podemos observar que 40% dos passageiros que embarcam em Frankfurt tendem a desembarcar em Munique, enquanto os outros 60% tendem a ir para Colônia. Entre os passageiros em Colônia, 30% tendem a retornar a Frankfurt, e 70% normalmente seguem para Berlim. Este modelo destaca claramente as rotas mais populares usadas pelos seus clientes.
Além disso, observe que há destinos sem conexões diretas. A ausência de uma conexão indica que, ao longo dos 70 anos da empresa, nenhum cliente precisou viajar diretamente entre essas duas cidades. Portanto, como gerente, você pode concluir com confiança que adicionar ônibus de Frankfurt para Berlim pode não ser tão lucrativo quanto outras rotas populares, como Frankfurt para Colônia.
O ponto ilustrado é que uma matriz de transição mostra as diferentes probabilidades de transição de um estado para outro. De acordo com Andrey Markov, a probabilidade de qualquer estado depende apenas do seu estado atual. Ela nos ajuda a entender como um sistema muda e qual estado é mais provável de ocorrer em seguida. Antes de aplicarmos matrizes de transição aos mercados financeiros, devemos primeiro definir todos os possíveis estados que o mercado pode estar.
Construindo Nossa Estratégia: Definindo os Estados do Mercado
Uma forma eficaz de definir os estados do mercado é usando indicadores técnicos. No exemplo abaixo, aplicamos uma média móvel a um símbolo do nosso Terminal MetaTrader 5. Podemos definir os estados da seguinte forma: "Sempre que uma vela fecha acima da média móvel, o estado é ALTA (1 no diagrama), e sempre que uma vela fecha abaixo da média móvel, o estado é BAIXA (2 no diagrama)."
Fig 3: Um diagrama esquemático mostrando o estado do mercado como sendo 1 ou 2.
Podemos construir uma Cadeia de Markov para modelar como o mercado transita de fechar acima da média móvel para fechar abaixo dela. Em outras palavras, uma Cadeia de Markov modelando a relação entre a média móvel e o preço de fechamento responderia a perguntas como: "Se uma vela fecha acima da média móvel, qual é a probabilidade de que a próxima vela também feche acima da média móvel?" Se essa probabilidade for superior a 0,5, o mercado pode ser adequado para estratégias de seguimento de tendência. Caso contrário, o mercado será mais adequado para estratégias de reversão à média.
Começando: Construindo Nossa Primeira Matriz de Transição
#Import packages
import pandas as pd
import numpy as np
import MetaTrader5 as mt5
from datetime import datetime
import pandas_ta as ta
import time
Em seguida, temos que definir nossas credenciais de login e especificar outras variáveis globais de interesse, como o símbolo que desejamos negociar e o intervalo de tempo que queremos usar.
#Account login details login = 123456789 password = "Enter Your Password" server = "Enter Your Server" symbol = "EURUSD" #What timeframe are we working on? timeframe = mt5.TIMEFRAME_M1 #This data frame will store the most recent price update last_close = pd.DataFrame() #We may not always enter at the price we want, how much deviation can we tolerate? deviation = 100 #The size of our positions volume = 0 #How many times the minimum volume should our positions be lot_multiple = 1
Agora, podemos fazer login.
#Login if(mt5.initialize(login=login,password=password,server=server)): print("Logged in successfully") else: print("Failed to login")
Seguindo, agora definimos nosso volume de negociação.
#Setup trading volume symbols = mt5.symbols_get() for index,symbol in enumerate(symbols): if symbol.name == "EURUSD": print(f"{symbol.name} has minimum volume: {symbol.volume_min}") volume = symbol.volume_min * lot_multiple
#Specify date range of data to be collected date_start = datetime(2020,1,1) date_end = datetime.now()
Após obtermos os dados, podemos agora prosseguir para calcular nossa matriz de transição para ver como o mercado EUR USD evolui.
#Fetch market data market_data = pd.DataFrame(mt5.copy_rates_range("EURUSD",timeframe,date_start,date_end)) market_data["time"] = pd.to_datetime(market_data["time"],unit='s') #Add simple moving average technical indicator market_data.ta.sma(length=20,append=True) #Delete missing rows market_data.dropna(inplace=True) #Inspect the data frame market_data
Fig 4: Nosso dataframe no formato atual.
Precisamos definir quanto de espaço deve haver entre as duas velas de interesse. Neste exemplo, estamos interessados em responder à pergunta: "Se a vela atual fechar acima da média móvel, qual é a probabilidade de que a próxima vela também feche acima da média móvel?" Se você estiver interessado nas probabilidades de transição em horizontes de tempo maiores, este é o parâmetro que você deve aumentar para atender às necessidades de sua estratégia específica.
#Define how far ahead we are looking look_ahead = 1
Calcular uma matriz de transição é fácil:
- Primeiro, defina todos os estados possíveis (definimos 2 estados simples, ALTA e BAIXA).
- Conte quantas velas se encaixam em cada estado respectivo.
- Calcule a proporção de todas as velas no estado ALTA que foram seguidas por outra vela no mesmo estado.
- Calcule a proporção de todas as velas no estado BAIXA que foram seguidas por outra vela no mesmo estado.
#Count the number of times price was above the moving average up = market_data.loc[market_data["close"] > market_data["SMA_20"]].shape[0] #Count the number of times price was below the moving average down = market_data.loc[market_data["close"] < market_data["SMA_20"]].shape[0] #Count the number of times price was above the moving average and remained above it up_and_up = (market_data.loc[( (market_data["close"] > market_data["SMA_20"]) & (market_data["close"].shift(-look_ahead) > market_data["SMA_20"].shift(-look_ahead)) )].shape[0]) / up #Count the number of times price was below the moving average and remained below it down_and_down = (market_data.loc[( (market_data["close"] < market_data["SMA_20"]) & (market_data["close"].shift(-look_ahead) < market_data["SMA_20"].shift(-look_ahead)) )].shape[0]) / downEm seguida, combinamos os dados em um dataframe.
transition_matrix = pd.DataFrame({ "UP":[up_and_up,(1-down_and_down)], "DOWN":[(1-up_and_up),down_and_down] },index=['UP','DOWN'])
Vamos visualizar nossa matriz de transição.
transition_matrix
Fig 5: Nossa matriz de transição.
Vamos interpretar a matriz de transição juntos. Nossa matriz está nos informando que, se a vela atual fechar acima da média móvel, há 88% de chance de que a próxima vela também feche acima da média móvel e 12% de chance de que a próxima vela feche abaixo da média móvel. Isso é um bom sinal de que os movimentos neste mercado específico não se reversam com frequência. Portanto, o mercado pode ser adequado para estratégias de seguimento de tendência.
Agora que construímos nossa matriz de transição, podemos construir o resto do nosso algoritmo, que usará essa matriz de transição para guiar suas decisões sobre se deve comprar ou vender um determinado ativo.
def get_prices():
start = datetime(2024,6,1)
end = datetime.now()
data = pd.DataFrame(mt5.copy_rates_range("EURUSD",timeframe,start,end))
#Add simple moving average technical indicator
data.ta.sma(length=20,append=True)
#Delete missing rows
data.dropna(inplace=True)
data['time'] = pd.to_datetime(data['time'],unit='s')
data.set_index('time',inplace=True)
return(data.iloc[-1,:])
Em seguida, definimos uma função para obter o estado atual do mercado.
def get_state(current_data): #Price is above the moving average, UP state if(current_data["close"] > current_data["SMA_20"]): return(1) #Price is below the moving average, DOWN state elif(current_data["close"] < current_data["SMA_20"]): return(2)
Por fim, definimos uma função para selecionar uma ação com base no estado atual do mercado e na probabilidade de transição.
def get_action(current_state): if(current_state == 1): if(transition_matrix.iloc[0,0] > transition_matrix.iloc[0,1]): print("The market is above the moving average and has strong trends, buy") print("Opening a BUY position") mt5.Buy("EURUSD",volume) elif(transition_matrix.iloc[0,0] < transition_matrix.iloc[0,1]): print("The market is above the moving average and has strong mean reverting moves, sell") print("Opening a sell position") mt5.Sell("EURUSD",volume) elif(current_state == 2): if(transition_matrix.iloc[1,0] > transition_matrix.iloc[1,1]): print("The market is below the moving average and has strong mean reverting moves, buy") print("Opening a BUY position") mt5.Buy("EURUSD",volume) elif(transition_matrix.iloc[1,0] < transition_matrix.iloc[1,1]): print("The market is below the moving average and has strong trends, sell") print("Opening a sell position") mt5.Sell("EURUSD",volume)
Agora podemos ver nosso algoritmo em ação.
while True: #Get data on the current state of our terminal and our portfolio positions = mt5.positions_total() #If we have no open positions then we can open one if(positions == 0): get_action(get_state(get_prices())) #If we have finished all checks then we can wait for one day before checking our positions again time.sleep(60)
O mercado está abaixo da média móvel e apresenta fortes tendências, venda.
Abrindo uma posição de venda.
Fig 6: A negociação selecionada pelo nosso algoritmo de negociação.
Fig 7: A negociação selecionada pelo nosso algoritmo de negociação no dia seguinte.
Isso não é tudo o que pode ser dito sobre matrizes de transição. No entanto, é uma boa introdução ao tópico. Antes de concluir nossa discussão, é importante que discutamos quais variáveis afetam nossa matriz de transição e como podemos manipular a matriz de transição, se necessário.
ALTA | BAIXA | |
---|---|---|
ALTA | 0.926 | 0.074 |
BAIXA | 0.043 | 0.957 |
Como você pode observar, quando selecionamos o EURUSD como nosso símbolo, a probabilidade de ver 2 velas consecutivas acima da média móvel era de 88%, mas agora, com este novo símbolo que selecionamos, "Boom 1000 Index", a probabilidade de ver 2 velas consecutivas acima da média móvel aumentou para 93%. Portanto, o símbolo escolhido tem um efeito inegável sobre a matriz de transição.
Os Parâmetros do Indicador TécnicoLembre-se de que usamos indicadores técnicos para nos ajudar a definir facilmente os estados do mercado em relação ao indicador. Portanto, alterar o período da média móvel afetaria muito a matriz de transição. Para ilustrar simplesmente o ponto, voltaremos às nossas condições iniciais de modelagem do EURUSD, mas desta vez a única diferença será que usaremos um período de 2, enquanto em nosso exemplo inicial usamos um período de 20. Todas as outras variáveis são mantidas constantes.
ALTA | BAIXA | |
---|---|---|
ALTA | 0.456 | 0.544 |
BAIXA | 0.547 | 0.453 |
Observe como as probabilidades de transição agora estão convergindo para chances de 50/50 de ir em qualquer direção. Isso nos diz implicitamente que, à medida que o período da média móvel aumenta, as probabilidades de transição se afastam cada vez mais de apenas chances de 50/50.
Espaço Entre as VelasEm nossa discussão, estávamos apenas preocupados com a relação entre duas velas consecutivas. No entanto, à medida que aumentamos o espaço entre as velas sob análise, nossa matriz de transição também muda. Novamente, voltaremos às condições iniciais que usamos para modelar o EURUSD, mas desta vez, aumentaremos o espaço entre as 2 velas para 100. Portanto, todas as outras variáveis permanecerão as mesmas, exceto pelo espaço entre as 2 velas.
ALTA | BAIXA | |
---|---|---|
ALTA | 0.503 | 0.497 |
BAIXA | 0.507 | 0.493 |
Recomendações
Não há uma forma ‘certa’ ou ‘errada’ de projetar sua Cadeia de Markov, no entanto, para que sua aplicação seja consistente com nossa discussão, é imprescindível seguir o padrão de design descrito abaixo ao construir suas Cadeias de Markov:transition_matrix = pd.DataFrame({ "UP":["UP AND UP","UP AND DOWN"], "DOWN":["DOWN AND UP","DOWN AND DOWN"] },index=['UP','DOWN'])
Nossa matriz de transição foi projetada para nos mostrar rapidamente se devemos seguir a tendência ou atuar contra as tendências.
Estratégias de seguimento de tendência podem funcionar melhor quando a diagonal principal contém as maiores probabilidades, isso significa que o mercado tende a pegar uma tendência e tende a permanecer nela:
Fig 8: Uma matriz de transição de seguimento de tendência.
Por outro lado, estratégias de reversão à média podem funcionar melhor quando a off-diagonal contém as maiores probabilidades, isso significa que o mercado tende a reverter para os níveis de equilíbrio:
Fig 9: Uma matriz de transição de reversão à média.
Além disso, se as maiores probabilidades estiverem encontradas na linha inferior, isso significa que o mercado é baixista:
Fig 10: Uma matriz de transição baixista.
Por fim, se as maiores probabilidades estiverem encontradas na linha superior, isso significa que o mercado é altista:
Fig 11: Uma matriz de transição altista.
Implementação em MQL5
Agora, prosseguiremos para implementar a estratégia usando MQL5 para que possamos testar extensivamente a estratégia com dados reais do mercado.
Primeiro, carregamos as bibliotecas que precisamos.
//+------------------------------------------------------------------+ //| Transition Matrices.mq5 | //| Gamuchirai Zororo Ndawana. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Gamuchirai Zororo Ndawana." #property link "https://www.mql5.com" #property version "1.00" //+------------------------------------------------------------------+ //|Overview | //+------------------------------------------------------------------+ /* This expert advisor will demonstrate how we can use transition matrices to build self optimizing expert advisors. Usaremos a matriz de transição para decidir se devemos empregar estratégias de seguimento de tendência ou de reversão à média. Gamuchirai Zororo Ndawana Friday 19 July 2024, 10:09 Selebi Phikwe Botswana */ //+------------------------------------------------------------------+ //| Libraries | //+------------------------------------------------------------------+ #include <Trade/Trade.mqh>//Trade class CTrade Trade;
Em seguida, definimos os parâmetros de entrada que podem ser editados pelo usuário final.
//+------------------------------------------------------------------+ //| Inputs | //+------------------------------------------------------------------+ input int fetch = 5; //How much historical data should we fetch? input int look_ahead = 1; //Our forecast horizon input int ma_period = 20; //The MA Period input int rsi_period = 20; //The RSI Period input int wpr_period = 20; //The Williams Percent Range Period input int lot_multiple = 20; //How big should the lot sizes be input double sl_width = 0.4; //Stop loss size
Avançando, existem variáveis globais que precisaremos em todo o nosso aplicativo.
//+------------------------------------------------------------------+ //|Global variables | //+------------------------------------------------------------------+ double minimum_volume;//Smallest lot size double ask_price;//Ask double bid_price;//Bid int ma_handler,rsi_handler,wpr_handler;//The handlers for our technical indicators vector ma_readings(fetch);//MA indicator values vector rsi_readings(fetch);//RSI indicator values vector wpr_readings(fetch);//WPR indicator values vector price_readings(fetch);//The vector we will use to store our historical price values matrix transition_matrix = matrix::Zeros(2,2);//The matrix to store our observations on price's transition behavior bool transition_matrix_initialized = false;//This flag will instruct the application to initialize the transition matrix double up_and_up = 0;//These variables will keep count of the price transitions double up_and_down = 0; double down_and_up = 0; double down_and_down = 0; double total_count = (double) fetch - look_ahead;//This variable will store the total number of observations used to calculate the transition matrix double trading_volume;//This is our desired trading size vector market_behavior = vector::Zeros(4);//Transition matrix interpretations
Precisamos definir a função de inicialização para o nosso Consultor Especialista. Esta função garantirá que o usuário forneceu entradas válidas e configurará nossos indicadores técnicos.
//+------------------------------------------------------------------+ //| Initialization Function | //+------------------------------------------------------------------+ int OnInit() { //--- Initialize the technical indicator ma_handler = iMA(_Symbol,PERIOD_CURRENT,ma_period,0,MODE_EMA,PRICE_CLOSE); rsi_handler = iRSI(_Symbol,PERIOD_CURRENT,rsi_period,PRICE_CLOSE); wpr_handler = iWPR(_Symbol,PERIOD_CURRENT,wpr_period); minimum_volume = SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN); trading_volume = minimum_volume * lot_multiple; //--- Look ahead cannot be greater than fetch if(look_ahead > fetch) { Comment("We cannot forecast further into the future than thr to total amount of data fetched.\nEither fetch more data or forecast nearer to the present."); return(INIT_FAILED); } //--- End of initialization return(INIT_SUCCEEDED); }
Nosso programa também precisa de um procedimento a ser seguido sempre que for desinicializado.
//+------------------------------------------------------------------+ //| Expert de-initialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- Remove technical indicators IndicatorRelease(rsi_handler); IndicatorRelease(wpr_handler); IndicatorRelease(ma_handler); //--- Remove Expert Advisor ExpertRemove(); }
Também criaremos uma função para atualizar nossos indicadores técnicos e buscar os preços atuais do mercado.
//+------------------------------------------------------------------+ //|This function will update our technical indicator values | //+------------------------------------------------------------------+ void update_technical_indicators(void) { //--- Update bid and ask price ask_price = SymbolInfoDouble(_Symbol,SYMBOL_ASK); bid_price = SymbolInfoDouble(_Symbol,SYMBOL_BID); //--- Update each indicator value, we only need the most recent reading rsi_readings.CopyIndicatorBuffer(rsi_handler,0,0,1); wpr_readings.CopyIndicatorBuffer(wpr_handler,0,0,1); ma_readings.CopyIndicatorBuffer(ma_handler,0,0,1); }
Lembre-se de que nossas interpretações das leituras dos indicadores técnicos sempre dependerão do comportamento do mercado, conforme medido pela matriz de transição.
//+------------------------------------------------------------------+ //|This function will find an entry opportunity based on our signals | | //+------------------------------------------------------------------+ void find_entry(void) { //--- Store the index of our largest entry ulong max_arg = market_behavior.ArgMax(); //--- First we have to know the behavior of the market before we decide to buy or sell if(max_arg == 0) { //--- This means that the market is bullish and we should probably only take buy oppurtunities Comment("The observed transition matrix can only be generated by a bullish market"); bullish_sentiment(0); } else if(max_arg == 1) { //--- This means that the market is bearish and we should probably only take sell oppurtunities Comment("The observed transition matrix can only be generated by a bearish market"); bearish_sentiment(0); } else if(max_arg == 2) { //--- This means that the market trends and we should probably join either side of the trend Comment("The observed transition matrix can only be generated by a trending market"); bearish_sentiment(0); bullish_sentiment(0); } else if(max_arg == 3) { //--- This means that the market is mean reverting and we should probably play against the trends on either side Comment("The observed transition matrix can only be generated by a mean reverting market"); bearish_sentiment(-1); bullish_sentiment(-1); } }
Precisamos de uma função para executar nossas ordens de compra.
//+----------------------------------------------------------------+ //|This function will look for oppurtunities to buy | //+----------------------------------------------------------------+ void bullish_sentiment(int f_flag) { //--- This function analyses the market for bullish sentiment using our technical indicator //--- It has only 1 parameter, a flag denoting whether we should interpret the indicators in a trend following fashion //--- or a mean reverting fashion. For example 0 means interpret the indicators in a trend following fashion. //--- Therefore if we call the function and pass 0, RSI readings above 50 will trigger buy orders. //--- However if -1 was passed then RSI readings below 50 will trigger buy orders. //--- First make sure we have no open positions if(PositionsTotal() > 0) { return; } //--- Interpret the flag if(f_flag == 0) { //--- The flag is telling us to follow the trend if((rsi_readings[0] > 50) && (wpr_readings[0] > -50)) { Trade.Buy(trading_volume,_Symbol,ask_price,(ask_price - sl_width),(ask_price + sl_width),"Transition Matrix Order"); } } else if(f_flag == -1) { //--- The flag is telling us to bet against the trend if((rsi_readings[0] < 50) && (wpr_readings[0] < -50)) { Trade.Buy(trading_volume,_Symbol,ask_price,(ask_price - sl_width),(ask_price + sl_width),"Transition Matrix Order"); } } }
Esta função executará nossas ordens de venda para nós. Lembre-se de que, se nosso mercado for de reversão à média, interpretaremos os indicadores de forma "oposta".
//+-------------------------------------------------------------+ //|This function will help us find oppurtunities to sell | //+-------------------------------------------------------------+ void bearish_sentiment(int f_flag) { //--- This function analysises the market for bearish sentiment using our technical indicator //--- It has only 1 parameter, a flag denoting whether we should interpret the indicators in a trend following fashion //--- or a mean reverting fashion. For example 0 means interpret the indicators in a trend following fashion. //--- Therefore if we call the function and pass 0, RSI readings below 50 will trigger sell orders. //--- However if -1 was passed then RSI readings above 50 will trigger sell orders. //--- First make sure we have no open positions if(PositionsTotal() > 0) { return; } //--- Interpret the flag if(f_flag == 0) { //--- Now we know how to interpret our technical indicators if((rsi_readings[0] < 50) && (wpr_readings[0] < -50)) { Trade.Sell(trading_volume,_Symbol,bid_price,(bid_price + sl_width),(bid_price - sl_width),"Transition Matrix Order"); } } else if(f_flag == -1) { //--- Now we know how to interpret our technical indicators if((rsi_readings[0] > 50) && (wpr_readings[0] > -50)) { Trade.Sell(trading_volume,_Symbol,bid_price,(bid_price + sl_width),(bid_price - sl_width),"Transition Matrix Order"); } } }
Vamos também definir uma função que garantirá que nossa matriz de transição seja preparada e calculada de acordo com o procedimento que delineamos acima.
//+---------------------------------------------------------------+ //|This function will initialize our transition matrix | //+---------------------------------------------------------------+ void initialize_transition_matrix(void) { //--- We need to update our historical price readings and our MA readings ma_readings.CopyIndicatorBuffer(ma_handler,0,1,fetch); price_readings.CopyRates(_Symbol,PERIOD_CURRENT,COPY_RATES_CLOSE,1,fetch); //--- Now let us update our transition matrix for(int i = 0; i < fetch - look_ahead; i++) { //--- Did price go from being above the MA but end up beneath the MA? if((price_readings[i] > ma_readings[i]) && (price_readings[i + look_ahead] < ma_readings[i + look_ahead])) { up_and_down += 1; } //--- Did price go from being above the MA and remain above it? else if((price_readings[i] > ma_readings[i]) && (price_readings[i + look_ahead] > ma_readings[i + look_ahead])) { up_and_up += 1; } //--- Did price go from being below the MA but end up above it? else if((price_readings[i] < ma_readings[i]) && (price_readings[i + look_ahead] > ma_readings[i + look_ahead])) { down_and_up += 1; } //--- Did price go from being below the MA and remain below it? else if((price_readings[i] < ma_readings[i]) && (price_readings[i + look_ahead] < ma_readings[i + look_ahead])) { down_and_down += 1; } } //--- Let us see our counts so far Print("Up and up: ",up_and_up,"\nUp and down: ",up_and_down,"\nDown and up: ",down_and_up,"\nDown and down: ",down_and_down); double sum_of_counts = up_and_up + up_and_down + down_and_up + down_and_down; Print("Sum of counts: ",(sum_of_counts),"\nObservations made: ",total_count,"\nDifference:[the difference should always be 0] ",(total_count - sum_of_counts)); //--- Now we will calculate the transition matrix //--- The matrix position (0,0) stores the probaility that after making a move up, the market will continue rising //--- The matrix position (0,1) stores the probability that after making a move down, price will reverse and start rising //--- The matrix position (1,0) stores the probability that after making a move up, price will reverse and start falling //--- The matrix position (1,1) stores the probabilty that after making a move down, price will continue falling transition_matrix[0][0] = up_and_up / (up_and_up + up_and_down); transition_matrix[0][1] = down_and_up / (up_and_up + up_and_down); transition_matrix[1][0] = up_and_down / (down_and_up + down_and_down); transition_matrix[1][1] = down_and_down / (down_and_up + down_and_down); //--- Show the transition matrix Print("Our transition Matrix"); Print(transition_matrix); //--- Now we need to make sense of the transition matrix analyse_transition_matrix(); //--- Now we need to update the flag transition_matrix_initialized = true; }
Também precisamos de uma função auxiliar para interpretar nossa matriz de transição.
//+-------------------------------------------------------------+ //|This function will analyse our transition matrix | //+-------------------------------------------------------------+ void analyse_transition_matrix(void) { //--- Check if the market is bullish if((transition_matrix[0][0] > transition_matrix[1][0])&&(transition_matrix[0][1] > transition_matrix[1][1])) { market_behavior[0] = 1; } //--- Check if the market is bearish else if((transition_matrix[0][1] > transition_matrix[1][0])&&(transition_matrix[1][1] > transition_matrix[1][0])) { market_behavior[1] = 1; } //--- Check if the market trends else if(transition_matrix.Trace() > 1) { market_behavior[2] = 1; } //--- Check if the market is mean reverting else if(transition_matrix.Trace() < 1) { market_behavior[3] = 1; } } //+------------------------------------------------------------------+
Nosso manipulador OnTick garantirá que todas as funções que delineamos acima sejam chamadas no momento apropriado.
//+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- First we must check if our transition matrix has been initialized if(!transition_matrix_initialized) { initialize_transition_matrix(); } //--- Otherwise our transition matrix has been initialized else { //--- Update technical indicator values update_technical_indicators(); //--- If we have no open positions we will use our tranistion matrix to help us interpret our technical indicators if(PositionsTotal() == 0) { find_entry(); } } } //+------------------------------------------------------------------+
Fig 12: Nossa Matriz de Transição calculada em MQL5.
Fig 13: Nosso Consultor Especialista negociando o par AUDJPY.
Conclusão
Este artigo explora a aplicação das Cadeias de Markov na negociação algorítmica para se adaptar às mudanças nas condições do mercado. Começando com uma introdução ao conceito de Cadeias de Markov, ilustramos sua utilidade na modelagem de processos aleatórios semelhantes à dinâmica do mercado. Ao definir os estados do mercado usando indicadores técnicos, como médias móveis, mostramos como construir uma Cadeia de Markov para analisar as transições do mercado. Essa abordagem nos permite determinar a probabilidade de movimentos futuros do mercado, ajudando-nos a decidir se devemos empregar estratégias de seguimento de tendência ou de reversão à média. Por meio deste método, buscamos criar algoritmos de negociação inteligentes com habilidades aprimoradas de tomada de decisão, melhorando, em última análise, o desempenho de negociação em mercados dinâmicos.
Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/15040
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
Bem, como você sabe, há muitas maneiras de fazer qualquer coisa. A abordagem que descrevi aqui tem o objetivo de ajudá-lo a obter resultados confiáveis e rápidos. No entanto, tudo tem um preço, a matriz de transição que você observará é muito influenciada pela quantidade de dados que você obteve, mas, à medida que você obtém mais e mais dados, a matriz de transição se torna estável e para de mudar (ela converge).
Deixe-me explicar da seguinte forma: a matriz de transição e a abordagem NN estão resolvendo problemas totalmente diferentes, respondendo a perguntas diferentes. A matriz de transição não está prevendo nada, ela está simplesmente resumindo/dizendo o que aconteceu no passado e não nos diz o que provavelmente acontecerá no futuro.
A NN, por outro lado, está nos dizendo o que provavelmente acontecerá no futuro. É possível usar os dois em um EA.