English Русский 中文 Español Deutsch 日本語
preview
Construa Consultores Especialistas Autossustentáveis com MQL5 e Python

Construa Consultores Especialistas Autossustentáveis com MQL5 e Python

MetaTrader 5Exemplos |
236 3
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana

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?

O século 19 foi uma era de descobertas brilhantes, como a invenção do telefone por Alexander Graham Bell, a criação da lâmpada elétrica por Thomas Edison e o desenvolvimento do rádio por Guglielmo Marconi. No entanto, entre todas as inovações científicas daquela época, poucas são mais significativas para nós, como desenvolvedores algorítmicos, do que as contribuições do brilhante matemático russo Andrey Markov.

Markov

Fig 1: Uma foto de um jovem Andrey Markov.

Markov trabalhou em muitos problemas que exigiam que ele modelasse processos completamente aleatórios, semelhantes ao nosso desafio de lidar com a imprevisibilidade da dinâmica do mercado. Ele descreveu formalmente uma estrutura que é conhecida hoje como a “Cadeia de Markov”. Vamos entendê-la intuitivamente.

Imagine que você gerencia uma empresa de transporte público que fornece serviços de ônibus na Alemanha há mais de 70 anos. A empresa está considerando adicionar mais ônibus à frota, e você, como gerente, deve decidir quais destinos devem receber os ônibus adicionais e quais não valem mais investimento.

Abordar o problema como uma Cadeia de Markov pode simplificar o processo de tomada de decisão para você, como gerente. Vamos imaginar que o diagrama a seguir representa a Cadeia de Markov de todas as viagens realizadas pela empresa ao longo de seus 70 anos de história.


Modelo de 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)."


Definindo os Estados do Mercado

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

Para começar, iniciamos importando nossas bibliotecas padrão do Python para comunicação com nosso terminal MetaTrader5 e para análise de dados.

#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")
Login realizado com sucesso.

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
EURUSD tem volume mínimo: 0,01
Agora, precisamos especificar quanto de dados precisamos de nosso Terminal MetaTrader5.
#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

Nosso dataframe

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:

  1. Primeiro, defina todos os estados possíveis (definimos 2 estados simples, ALTA e BAIXA).
  2. Conte quantas velas se encaixam em cada estado respectivo.
  3. Calcule a proporção de todas as velas no estado ALTA que foram seguidas por outra vela no mesmo estado.
  4. 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]) / down
Em 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

Matriz de Transição

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. 

Primeiro, definimos uma função que buscará os dados de preços atuais do nosso terminal e calculará os valores dos indicadores técnicos.

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.

Condições Iniciais do Mercado

Fig 6: A negociação selecionada pelo nosso algoritmo de negociação.


Nossa negociação no dia seguinte.

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.


O Símbolo
A primeira variável que afeta nossa matriz de transição é, obviamente, o símbolo escolhido. Por exemplo, se mantivermos todas as outras variáveis iguais e simplesmente selecionarmos um novo símbolo, "Boom 1000 Index", isso é como nossa matriz de transição ficará agora.



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écnico

Lembre-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 Velas

Em 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:

Seguimento de tendência

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:

Reversão à média

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:


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:

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();
        }
     }
  }
//+------------------------------------------------------------------+

Matriz de Transição

Fig 12: Nossa Matriz de Transição calculada em MQL5.

Testando nosso EA

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

Últimos Comentários | Ir para discussão (3)
Sibusiso Steven Mathebula
Sibusiso Steven Mathebula | 26 jul. 2024 em 03:38
No artigo acima, matrizes e vetores foram usados para otimizar uma estratégia de negociação sem necessariamente usar a abordagem de rede neural convencional. Parece que (pelo menos para mim) é possível criar um EA auto-otimizado sem necessariamente usar NN que envolva funções de ativação, o que significa que você não precisa realmente de funções de ativação ou neurônios para auto-otimizar seu EA. É muito provável que eu seja corrigido. Eu poderia estar definitivamente errado, eu poderia estar realmente muito errado, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, ........... estar entendendo tudo errado sobre otimização e NN mate......Eu sou seu vizinho, aqui na RSA.
Gamuchirai Zororo Ndawana
Gamuchirai Zororo Ndawana | 27 jul. 2024 em 11:14
Sibusiso Steven Mathebula estratégia de negociação sem necessariamente usar a abordagem de rede neural convencional. Parece que (pelo menos para mim) é possível criar um EA auto-otimizado sem necessariamente usar NN que envolva funções de ativação, o que significa que você não precisa realmente de funções de ativação ou neurônios para auto-otimizar seu EA. É muito provável que eu seja corrigido. Eu poderia estar definitivamente errado, eu poderia estar realmente muito errado, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, eu poderia, ........... estar entendendo tudo errado sobre otimização e NN mate......Eu sou seu vizinho, aqui na RSA.
Ei SIbusiso, Ujani Budi?

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.
thiezo
thiezo | 1 jan. 2025 em 07:09
Oi Gamuchirai. Este artigo fala diretamente a mim e eu lhe agradeço por abrir nossas mentes. Sou muito novo em codificação e aprendo lendo e codificando a partir de artigos como o seu. Meu maior desafio é o Python. Não sei nem por onde começar, especialmente porque aprendo mais rápido quando o assunto é negociação, pois assim posso fazer backtest e incorporar ideias em meu EA. Por favor, me indique onde posso aprender a linguagem. Só codifiquei a versão MQL5 e o problema que enfrento é que 'max_arg' permanece 0, portanto, o EA permanece em alta. Com meu conhecimento limitado, tentei manipular alguns parâmetros e parei em um ponto em que o código colocaria uma compra e uma venda ao mesmo tempo. Talvez eu esteja perdendo um detalhe crucial. Posso lhe enviar meu código copiado e/ou modificado se o código funcionar corretamente do seu lado. Talvez você consiga identificar o problema. Uso dados baixados, pois estou de férias e, portanto, trabalhando off-line. Isso poderia causar problemas? Agradeço o trabalho que você está fazendo e seus artigos são brilhantes. Sou da África do Sul e tudo o que posso dizer é obrigado, tsano.
Redes neurais em trading: Detecção de objetos com reconhecimento de cena (HyperDet3D) Redes neurais em trading: Detecção de objetos com reconhecimento de cena (HyperDet3D)
Apresentamos uma nova abordagem para a detecção de objetos por meio de hiper-redes. Uma hiper-rede de geração de pesos para o modelo subjacente, que nos permite levar em conta as peculiaridades do estado atual do mercado. Essa abordagem melhora a precisão da previsão, adaptando o modelo a diferentes condições de mercado.
Análise causal de séries temporais usando entropia de transferência Análise causal de séries temporais usando entropia de transferência
Neste artigo, discutimos como a causalidade estatística pode ser aplicada para identificar variáveis preditivas. Exploraremos a relação entre causalidade e entropia de transferência, além de apresentar um código MQL5 para detectar transferências direcionais de informação entre duas variáveis.
Otimização de nuvens atmosféricas — Atmosphere Clouds Model Optimization (ACMO): Teoria Otimização de nuvens atmosféricas — Atmosphere Clouds Model Optimization (ACMO): Teoria
Este artigo é dedicado ao algoritmo meta-heurístico Atmosphere Clouds Model Optimization (ACMO), que modela o comportamento das nuvens para resolver problemas de otimização. O algoritmo utiliza os princípios de geração, movimento e dispersão de nuvens, adaptando-se às "condições climáticas" no espaço de soluções. O artigo explora como a simulação meteorológica do algoritmo encontra soluções ótimas em um espaço complexo de possibilidades e descreve detalhadamente as etapas do ACMO, incluindo a preparação do "céu", o nascimento das nuvens, seu deslocamento e a concentração de chuva.
Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 7): Refinando nosso modelo para o desenvolvimento de EA Construindo um Modelo de Restrição de Tendência de Candlestick (Parte 7): Refinando nosso modelo para o desenvolvimento de EA
Neste artigo, vamos nos aprofundar na preparação detalhada do nosso indicador para o desenvolvimento de Expert Advisor (EA). Nossa discussão abrangerá refinamentos adicionais na versão atual do indicador para melhorar sua precisão e funcionalidade. Além disso, vamos introduzir novos recursos que marcam pontos de saída, abordando uma limitação da versão anterior, que identificava apenas os pontos de entrada.