English Русский 中文 Español Deutsch 日本語
preview
Relembrando a antiga estratégia de tendência: dois osciladores estocásticos, MA e Fibonacci

Relembrando a antiga estratégia de tendência: dois osciladores estocásticos, MA e Fibonacci

MetaTrader 5Sistemas de negociação | 15 novembro 2023, 10:02
517 0
Javier Santiago Gaston De Iriarte Cabrera
Javier Santiago Gaston De Iriarte Cabrera

Introdução à estratégia

Esta estratégia é puramente técnica e utiliza vários indicadores e ferramentas para gerar sinais e determinar níveis-alvo. Os componentes da estratégia incluem:

  • Oscilador estocástico de 14 períodos.
  • Oscilador estocástico de cinco períodos.
  • Média móvel de 200 períodos.
  • Projeção de Fibonacci (para definição dos níveis-alvo).

O oscilador estocástico é uma ferramenta popular de análise técnica usada por traders e investidores para medir o ímpeto e a força dos movimentos de preços de um instrumento financeiro. Foi desenvolvido por George Lane no final dos anos 1950. O estocástico varia de 0 a 100, com valores próximos à parte inferior chamados de níveis de sobrevenda (viés de alta) e valores próximos à parte superior chamados de níveis de sobrecompra (viés de baixa).

O oscilador estocástico de cinco períodos no gráfico diário é calculado da seguinte forma:

Stoch

onde High e Low são os preços mais altos e mais baixos dos últimos 5 dias, respectivamente, e %D é a média móvel de %K dos últimos N dias (os últimos N valores de %K). Geralmente, isso é uma média móvel simples, mas também pode ser uma média móvel exponencial com um peso menos padronizado para valores mais recentes. Ao trabalhar exclusivamente com %D, há apenas um sinal confiável - divergência entre %D e o ativo em análise.

A média móvel é uma ferramenta estatística amplamente utilizada que ajuda a suavizar os dados de preços ao longo de um período de tempo específico. É amplamente utilizado em várias áreas, incluindo finanças, economia e processamento de sinais. No contexto dos mercados financeiros, as médias móveis são frequentemente usadas na análise técnica para identificar tendências e gerar sinais de negociação.

A média móvel é calculada usando a média dos preços ao longo de um período de tempo específico e é atualizada à medida que novos dados são recebidos. À medida que cada novo ponto de dados é adicionado, o ponto mais antigo é removido, resultando em uma "média móvel" que reflete os preços mais recentes.


Implementação da estratégia

As regras da estratégia são as seguintes:

  • Um sinal de compra é gerado sempre que ambos os osciladores estocásticos atingem simultaneamente o nível de sobrevenda, fazem um rebote e depois retornam a ele (aproximadamente ao mesmo tempo). Tudo isso deve acontecer enquanto o mercado estiver acima da média móvel de 200 períodos. O primeiro nível-alvo é definido usando a projeção de Fibonacci, aplicada a partir do mínimo da primeira vez que os osciladores estocásticos atingiram o fundo e do mínimo da segunda vez que atingiram o fundo. Logo, o primeiro alvo é a projeção de 61,8%, e o segundo alvo é a projeção de 100,0%.
  • Um sinal de venda é gerado sempre que ambos os osciladores estocásticos atingem simultaneamente o nível de sobrecompra, fazem um rebote e depois retornam a ele (aproximadamente ao mesmo tempo). Tudo isso deve acontecer enquanto o mercado estiver abaixo da média móvel de 200 períodos. O primeiro nível-alvo é definido usando a projeção de Fibonacci, aplicada a partir do máximo da primeira vez que os osciladores estocásticos atingiram o topo e do máximo da segunda vez que atingiram o topo. Logo, o primeiro alvo é a projeção de 61,8%, e o segundo alvo é a projeção de 100,0%.

(Fiz alterações na estratégia para incluir níveis de stop em cada nível de Fibonacci)

A figura a seguir mostra um sinal de baixa:

bearish


Em última análise, os resultados podem variar de mercado para mercado, e os resultados atuais podem ser instáveis. Há estratégias que funcionam em determinados períodos, mas podem ser ineficazes em outros.

A parada da estratégia é realizada ou a meio do alvo, para alcançar uma relação de risco e recompensa de 2,0, ou sempre que o mercado rompe a linha da média móvel.

Na negociação, os níveis de correção de Fibonacci são um método de análise técnica para determinar níveis de suporte e resistência. Eles são nomeados após a sequência de números de Fibonacci, cujas proporções determinam os níveis de preço para os quais os mercados tendem a retornar antes que a tendência continue na direção original.

A previsão de correção de Fibonacci é criada usando dois pontos extremos no gráfico e dividindo a distância vertical pelos coeficientes de Fibonacci. 0% é considerado o início da correção, e 100% é a reversão completa para o preço inicial antes do movimento. Existem linhas horizontais que são desenhadas no gráfico (não neste EA) para esses níveis de preço, a fim de fornecer níveis de suporte e resistência.

Os níveis comuns são 23,6%, 38,2%, 50% e 61,8%.


Resultados

Embora esta seja uma estratégia lucrativa, os resultados variam de mercado para mercado e podem ser instáveis. Há estratégias que funcionam em determinados períodos, mas podem ser ineficazes em outros. Por favor, teste a estratégia antes de usá-la e ajuste os valores, como o período de tempo, de acordo com os melhores resultados.

Podemos usar o seguinte código para mover todos os dados 

   int Highest = iHighest(Symbol(),my_timeframe,MODE_CLOSE,shift,1);
   double High0=iHigh(Symbol(),my_timeframe,0);


   int Lowest = iLowest(Symbol(),my_timeframe,MODE_CLOSE,shift,1);
   double Low0=iLow(Symbol(),my_timeframe,0);

Mas para fins de teste, usaremos um valor menor de deslocamento (por exemplo, 300).

Estes são os resultados para um deslocamento de 300, período de 30 minutos, de 2013 a 2023 (20 de junho) e risco de 2%.

Gráfico

data

No mundo das finanças, o Índice de Sharpe (também conhecido como taxa de Sharpe ou relação de recompensa-variabilidade) mede a eficiência de investimentos, como ações ou portfólios, em comparação com um ativo sem risco, após ajuste para o risco. É calculado como a diferença entre o retorno do investimento e o retorno sem risco, dividido pelo desvio padrão do retorno do investimento. O índice representa o valor adicional de retorno que um investidor obtém por unidade adicional de risco.

sharpe



Código

No OnInit, declaramos as características técnicas que planejamos usar, identificadores:

void OnInit()
  {
   Stochastic_handle1 = iStochastic(_Symbol, PERIOD_CURRENT, Signal_0_Stoch_PeriodK, Signal_0_Stoch_PeriodD, Signal_0_Stoch_PeriodSlow, MODE_SMA, STO_LOWHIGH);
   Stochastic_handle2 = iStochastic(_Symbol, PERIOD_CURRENT, Signal_1_Stoch_PeriodK, Signal_1_Stoch_PeriodD, Signal_1_Stoch_PeriodSlow, MODE_SMA, STO_LOWHIGH);

//--- create handle of the indicator iMA
   handle_iMA=iMA(_Symbol,PERIOD_CURRENT,Inp_MA_ma_period,Inp_MA_ma_shift,
                  Inp_MA_ma_method,Inp_MA_applied_price);


//Test

   Alert("Expert Advisor has been launched");

  }

Este código cria um identificador para o indicador Estocástico. I identificador é chamado Stochastic_handle1. Para criá-lo, usamos a função iStochastic(). Os seguintes parâmetros são passados para a função: símbolo, período atual, período da linha %K, período da linha %D, período da linha lenta, modo da linha lenta e tipo de estocástico (baixo/alto).

Este código é usado para calcular a Média Móvel (MA) do símbolo atual com os parâmetros especificados. A variável handle_iMA armazena o resultado do cálculo da MA. Os parâmetros usados no cálculo são o símbolo, o período atual, o período da MA, o deslocamento da MA, o método da MA e o preço aplicado. O símbolo é o par de moedas ou o instrumento financeiro para o qual a MA está sendo calculada. O período atual é o período de tempo do gráfico para o qual a MA está sendo calculada. O período da MA é o número de barras usadas no cálculo da MA. O deslocamento da MA é o número de barras pelo qual o cálculo da MA é deslocado. O método da MA é o tipo de cálculo da MA, como simples, exponencial, suavizada ou ponderada. O preço aplicado é o tipo de preço usado no cálculo da MA, como Close (fechamento), Open (abertura), High (máximo), Low (mínimo), Median (mediana), Typical (típico) ou Weighted (ponderado).

Todos esses parâmetros precisam ser introduzidos, declarados fora da função OnInit.


No evento OnTick, os utilizaremos para obter os valores de cada tick.

   MqlTick tick;
   SymbolInfoTick(_Symbol,tick);

Este código é usado para obter os dados de tick para o símbolo atual. Na primeira linha, declara-se uma variável MqlTick chamada tick. A segunda linha chama a função SymbolInfoTick(), que recebe dois parâmetros, o nome do símbolo e a variável tick. A função obtém os dados de tick para o símbolo atual e os armazena na variável tick.


Usaremos o seguinte código para modelar os níveis de correção de Fibonacci:

int Highest = iHighest(Symbol(),my_timeframe,MODE_CLOSE,shift,1);
   double High0=iHigh(Symbol(),my_timeframe,0);


   int Lowest = iLowest(Symbol(),my_timeframe,MODE_CLOSE,shift,1);
   double Low0=iLow(Symbol(),my_timeframe,0);



   double highestValue = iHigh(Symbol(),my_timeframe,Highest);


   double lowestValue = iLow(Symbol(),my_timeframe,Lowest);
// Obtener el valor más alto y más bajo de la barra actual
   double currentHigh = High0;
   double currentLow = Low0;

// Obtener el valor más alto y más bajo de la barra anterior
   double previousHigh = highestValue;
   double previousLow = lowestValue;


   double level0s = currentHigh;
   double level1s = currentHigh - (currentHigh - previousLow) * 0.236;
   double level2s = currentHigh - (currentHigh - previousLow) * 0.382;
   double level3s = currentHigh - (currentHigh - previousLow) * 0.618;
   double level4s = previousLow;

   double level0b = currentLow;
   double level1b = currentLow + (-currentLow + previousHigh) * 0.236;
   double level2b = currentLow + (-currentLow + previousHigh) * 0.382;
   double level3b = currentLow + (-currentLow + previousHigh) * 0.618;
   double level4b = previousHigh;

Este código em linguagem MQL5 é usado para determinar os valores máximos e mínimos do símbolo e do período atual. As duas primeiras linhas de código atribuem o valor máximo do símbolo e do período à variável Highest, e o valor máximo do símbolo e do período com deslocamento=0 à variável High0 (candle atual). As duas linhas seguintes atribuem o valor mínimo do símbolo e do período à variável Lowest, e o valor mínimo do símbolo e do período com deslocamento=0 à variável Low0.


Usaremos o deslocamento para selecionar quantas velas olharemos para trás.

Para a Média Móvel, usaremos o seguinte código:

//---
   double array_ma[];
   ArraySetAsSeries(array_ma,true);
   int start_pos=0,count=3;
   if(!iGetArray(handle_iMA,0,start_pos,count,array_ma))
      return;

Este código é usado para obter um array de Médias Móveis a partir do identificador (handle). Na primeira linha, declara-se um array array_ma que será usada para armazenar as Médias Móveis. A segunda linha define o array como uma série. As terceira e quarta linhas declaram duas variáveis inteiras start_pos e count que serão usadas para especificar a posição inicial e a quantidade de elementos a serem extraídos do identificador. A quinta linha usa a função iGetArray para obter as Médias Móveis do identificador e as armazenar em array_ma. A função retorna false se não conseguir obter as Médias Móveis.

O código a seguir (fora do OnInit)

bool iGetArray(const int handle,const int buffer,const int start_pos,
               const int count,double &arr_buffer[])
  {
   bool result=true;
   if(!ArrayIsDynamic(arr_buffer))
     {
      //if(InpPrintLog)
      PrintFormat("ERROR! EA: %s, FUNCTION: %s, this a no dynamic array!",__FILE__,__FUNCTION__);
      return(false);
     }
   ArrayFree(arr_buffer);
//--- reset error code
   ResetLastError();
//--- fill a part of the iBands array with values from the indicator buffer
   int copied=CopyBuffer(handle,buffer,start_pos,count,arr_buffer);
   if(copied!=count)
     {
      //--- if the copying fails, tell the error code
      //if(InpPrintLog)
      PrintFormat("ERROR! EA: %s, FUNCTION: %s, amount to copy: %d, copied: %d, error code %d",
                  __FILE__,__FUNCTION__,count,copied,GetLastError());
      //--- quit with zero result - it means that the indicator is considered as not calculated
      return(false);
     }
   return(result);
  }

Este código é usado para copiar uma parte do buffer do indicador em um array. Ele recebe cinco parâmetros: identificador, buffer, posição inicial, contador e buffer do array. Primeiro, ele verifica se o buffer do array é dinâmico e, se não for, exibe uma mensagem de erro. Em seguida, ele redefine o código de erro e copia o buffer para o buffer do array. Se a soma copiada não for igual ao contador, uma mensagem de erro é impressa e false é retornado. Caso contrário, true é retornado.


Código para exibir resultados no gráfico:

   string text="";
   for(int i=0; i<count; i++)
      text=text+IntegerToString(i)+": "+DoubleToString(array_ma[i],Digits()+1)+"\n";
//---
   Comment(text);

Este código é usado para exibir valores de um array de tipo double em linguagem MQL5. O código começa declarando uma variável de string chamada "text" e atribuindo a ela uma string vazia. Em seguida, um laço "for" é usado para iterar sobre o array, com a variável "i" sendo usada como contador do laço. Para cada iteração, o valor de "i" é convertido em uma string usando a função "IntegerToString()", e o valor do array no índice correspondente é convertido em uma string usando a função "DoubleToString()". A função "Digits()" é usada para determinar o número de casas decimais usadas ao converter o valor double em uma string. Os valores convertidos são então concatenados na string "text", com um novo caractere de linha sendo adicionado após cada valor. Finalmente, a função "Comment()" é usada para imprimir a string "text".


Faremos o mesmo com ambos os osciladores estocásticos.

Configuraremos condições para que não seja aberta mais de uma ordem ao mesmo tempo:

   int total = PositionsTotal();

   if(total==0)
{
...code
}

   if(total>0)
{
...code
}

Para abrir ordens, usaremos o seguinte código:

if(!trade.Buy(get_lot(tick.bid),_Symbol,tick.bid,newStopLossLevelb1,newTakeProfitLevelb2))
                 {
                  //--- failure message
                  Print("Buy() method failed. Return code=",trade.ResultRetcode(),
                        ". Code description: ",trade.ResultRetcodeDescription());
                 }
               else
                 {
                  Print("Buy() method executed successfully. Return code=",trade.ResultRetcode(),
                        " (",trade.ResultRetcodeDescription(),")");
                 }

Aqui, usaremos sequencialmente Ticket.bid, bem como SL (Stop Loss) e TP (Take Profit). TP será o máximo mais alto do período de deslocamento, e SL será o mínimo da vela atual.

Para fechar uma ordem quando o preço cruzar a MA, usaremos o seguinte código:

if(rates[1].close >array_ma22[0])
           {

            trade.PositionClose(_Symbol,5);
            Print("cerro");
            return;
           }
         else
            return;

        }

Para modificar TP e SL, usaremos o código:

            //--- setting the operation parameters
            request.action  =TRADE_ACTION_SLTP; // type of trade operation
            request.position=position_ticket;   // ticket of the position
            request.symbol=position_symbol;     // symbol
            request.sl      =newStopLossLevelss;                  // Stop Loss of the position
            request.tp      =newTakeProfitLevelss;               // Take Profit of the position
            request.magic=Expert_MagicNumber;         // MagicNumber of the position
            //--- output information about the modification
            PrintFormat("Modify #%I64d %s %s",position_ticket,position_symbol,EnumToString(type));
            //--- send the request
            if(!OrderSend(request,result))
               PrintFormat("OrderSend error %d",GetLastError());  // if unable to send the request, output the error code
            //--- information about the operation
            PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result.retcode,result.deal,result.order);

Não esqueça de usar o nível de congelamento e o nível de parada. Lembre-se também de ajustar tanto o TP quanto o SL, caso contrário, você receberá um erro.

Adicionei níveis de Stop Loss a todos os níveis de Fibonacci, então os resultados podem ser diferentes do ponto de partida original. Ao ler este código, você poderá modificá-lo e ajustar esses níveis.


Conclusão

A estratégia apresentada pode ser lucrativa em alguns períodos de tempo, mas pode ser ineficaz em outras circunstâncias. Durante a crise de 2008-2014 e a crise da COVID-19 em 2020, a estratégia se mostrou inadequada. 

A estratégia funciona bem em tempos não-crisis e em períodos de tendência.

Ela gera um índice de Sharpe de cerca de 4, o que significa que a estratégia é pelo menos confiável.

Você pode usá-la como complemento a outras estratégias.

Você pode personalizá-la de acordo com suas preferências.

O objetivo deste artigo é ajudar as pessoas a entenderem a estratégia. A estratégia não é destinada a ser usada. Aplique-a por sua própria conta e risco.

Eu recomendo testar este robô em vários períodos e em diferentes símbolos.

O uso de períodos diferentes provavelmente resultará em diferentes resultados.

Traduzido do Inglês pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/en/articles/12809

Arquivos anexados |
2Stoch_1MA.mq5 (77.39 KB)
Teoria das Categorias em MQL5 (Parte 13): Eventos de calendário com esquemas de banco de dados Teoria das Categorias em MQL5 (Parte 13): Eventos de calendário com esquemas de banco de dados
Neste artigo, discutimos como os esquemas de banco de dados podem ser incorporados para categorização em MQL5. Analisaremos brevemente como os conceitos de esquema de banco de dados podem ser combinados com a teoria da categoria na identificação de informações de texto (string) relevantes para a negociação. O foco será em eventos de calendário.
Desenvolvendo um sistema de Replay (Parte 35): Ajeitando as coisas (I) Desenvolvendo um sistema de Replay (Parte 35): Ajeitando as coisas (I)
Temos que corrigir algumas coisas antes de realmente poder continuar. Mas não se trata necessariamente de uma correção e sim de um aperfeiçoamento na forma de gerir e utilizar classe. O motivo é que existem falhas ocorrendo por conta de algum tipo de interação dentro do sistema. Apesar das tentativas de tentar compreender o motivo de algumas das falhas, para assim sana-las. Todas foram frustradas, já que não fazia o mínimo sentido de algumas delas estarem ocorrendo. Quando fazemos uso de ponteiros ou recursão em C / C++, e o programa começa a apresentar falhas.
Aprendendo PrintFormat() e obtendo exemplos prontos para uso Aprendendo PrintFormat() e obtendo exemplos prontos para uso
Este artigo será útil tanto para iniciantes quanto para desenvolvedores experientes. Nele, analisaremos a função PrintFormat(), veremos exemplos de formatação de strings e escreveremos modelos para a exibição de diferentes informações no log do terminal.
Redes neurais de maneira fácil (Parte 49): Soft Actor-Critic (SAC) Redes neurais de maneira fácil (Parte 49): Soft Actor-Critic (SAC)
Continuamos nossa exploração dos algoritmos de aprendizado por reforço na resolução de problemas em espaços de ação contínua. Neste artigo, apresento o algoritmo Soft Actor-Critic (SAC). A principal vantagem do SAC está em sua capacidade de encontrar políticas ótimas que não apenas maximizam a recompensa esperada, mas também têm a máxima entropia (diversidade) de ações.