Lógica Difusa nas estratégias de negociação

1 dezembro 2017, 08:58
Maxim Dmitrievsky
0
1 199

Introdução

Os traders geralmente se perguntam como melhorar um sistema de negociação ou como criar um novo sistema através da aprendizagem de máquina. Apesar da abundância de publicações, um método simples e intuitivo ainda não foi encontrado para criar modelos que não podem ser estimados analiticamente sem recorrer a cálculos auxiliados por computador. A lógica difusa é uma janela para o mundo da aprendizagem de máquinas. Combinado com algoritmos genéticos, ela é capaz de expandir as capacidades de criação de sistemas de autoaprendizagem ou de fácil otimização. Ao mesmo tempo, a lógica difusa é intuitiva, pois ela encapsula informações numéricas nítidas em termos difusos (desfocados), assim como uma pessoa faz no processo de pensar.

Aqui está um exemplo. Em termos de uma lógica nítida, a velocidade de um carro em movimento é determinada por dispositivos de medição: por exemplo, 60 km/h. Mas um observador casual sem dispositivos de medição só pode estimar a velocidade do carro com base em sua experiência ou base de conhecimento. Por exemplo, sabe-se que um carro pode correr rapidamente e "rápido" é definido aproximadamente como 100 km/h e acima. Sabe-se que um carro pode correr lentamente, que é entre 5-10 km/h. E, finalmente, a velocidade é visualmente estimada como média (cerca de 60 km/h) se o carro que se aproxima aumenta o seu tamanho a uma taxa moderada. Assim, é possível caracterizar 60 km/h com quatro expressões diferentes:

  • velocidade média;
  • velocidade próxima da média;
  • mais média do que rápida;
  • e, finalmente, mais média do que lenta.

É assim que a informação é encapsulada em uma consciência humana, permitindo que ele apreenda apenas as informações necessárias no momento atual, por exemplo: "eu terei tempo de atravessar a estrada se o carro estiver se movendo de forma não tão rápida? " Pensar em tudo ao mesmo tempo e em grande detalhe forçaria uma pessoa a gastar quantidades colossais de tempo e recursos energéticos antes de tomar qualquer decisão específica: atravesse a estrada ou deixe o carro passar. Ao mesmo tempo, a situação atual seria minuciosamente estudada, o que talvez nunca mais seja repetida de forma idêntica no futuro e teria apenas contornos semelhantes. Na aprendizagem de máquina, tais situações são chamadas de sobre-ajuste (overfitting).

Este artigo não aprofundará a teoria da lógica difusa. A informação sobre este tema está amplamente disponível na Internet e no site MQL5. Vamos começar com a prática imediatamente, o que será explicado com excertos teóricos e fatos curiosos.

Para construir um modelo, foi utilizado a biblioteca Fuzzy, disponível no pacote padrão do terminal MetaTrader 5.

O resultado será um EA pronto baseado na lógica difusa, que pode ser tomado como exemplo para a construção de sistemas personalizados.

Criação do protótipo do sistema de negociação

Vamos seguir com a criação da lógica nítida do sistema de negociação, que será usada como base em novas pesquisas. Então, dois sistemas idênticos podem ser comparados, onde o segundo utilizará a lógica difusa.

3 osciladores RSI com diferentes períodos serão utilizados como base:

hnd1 = iRSI(_Symbol,0,9,PRICE_CLOSE);
hnd2 = iRSI(_Symbol,0,14,PRICE_CLOSE);
hnd3 = iRSI(_Symbol,0,21,PRICE_CLOSE);

Vamos formular as condições nítidas dos sinais e defini-las na função:

double CalculateSignal()
{
 double res =0.5;
 CopyBuffer(hnd1,0,0,1,arr1);
 CopyBuffer(hnd2,0,0,1,arr2);
 CopyBuffer(hnd3,0,0,1,arr3);
 
 if(arr1[0]>70 && arr2[0]>70 && arr3[0]>70) res=1.0;                    // se todos os indicadores estiverem na área de sobrecompra, vende
 if(arr1[0]<30 && arr2[0]<30 && arr3[0]<30) res=0.0;                    // se todos os indicadores estiverem na área de sobrevenda, compra
 
 if(arr1[0]<30 && arr2[0]<30 && arr3[0]>70) res=0.5;                    // se 2 estão sobrevendidos e 1 está sobrecomprado, sem sinal
 if(arr1[0]<30 && arr2[0]>70 && arr3[0]<30) res=0.5;
 if(arr1[0]>70 && arr2[0]<30 && arr3[0]<30) res=0.5;
 
 if(arr1[0]>70 && arr2[0]>70 && arr3[0]<30) res=0.5;                    // se 2 são sobrecompra, e 1 é sobrevendido, sem sinal
 if(arr1[0]>70 && arr2[0]<30 && arr3[0]>70) res=0.5;
 if(arr1[0]<30 && arr2[0]>70 && arr3[0]>70) res=0.5;
 
 if(arr1[0]<30 && arr2[0]<30 && (arr3[0]>40 && arr3[0]<60)) res=0.0;    // se 2 estiverem sobrevendidos e o 3º na faixa dos 40 a 60, o sinal é de compra
 if(arr1[0]<30 && (arr2[0]>40 && arr2[0]<60) && arr3[0]<30) res=0.0;
 if((arr1[0]>40 && arr1[0]<60) && arr2[0]<30 && arr3[0]<30) res=0.0;
 
 if(arr1[0]>70 && arr2[0]>70 && (arr3[0]>40 && arr3[0]<60)) res=1.0;    // se 2 são sobrecompra, e o 3º está no intervalo de 40 a 60, o sinal é venda
 if(arr1[0]>70 && (arr2[0]>40 && arr2[0]<60) && arr3[0]>70) res=1.0;
 if((arr1[0]>40 && arr1[0]<60) && arr2[0]>70 && arr3[0]>70) res=1.0;
 
 return(res);
}


Em seguida, vamos escrever todas as outras funções de serviço e testar o EA a partir do início de 2017 no par EURUSD, tempo gráfico de М15 e М5 (todo o código do EA está anexado no final do artigo):

EURUSD M15

EURUSD M5

Mesmo que as condições nítidas para as combinações dos três indicadores tenham sido definidas e as condições sejam lógicas e consistentes, essa abordagem revelou-se muito direta e inflexível. Em média, o sistema não perde nem ganha por um período de 8 meses. Para fazê-lo ganhar, seria necessário recorrer a uma infinidade de combinações de condições, e possivelmente adicionar mais osciladores. Mas não há muito a ser otimizado, uma vez que as condições são definidas de forma extremamente precisa.

Vamos tentar ofuscar as ideias sobre as condições para tornar este sistema de negociação lucrativo usando a lógica difusa.

Criação do modelo de lógica difusa

Primeiro, é necessário incluir a biblioteca Fuzzy. Para ser exato, um dos dois modelos de lógica difusa disponíveis - Mamdani ou Sugeno. A diferença entre eles é que o Sugeno produz um modelo linear sem criar uma variável de saída na forma de um conjunto de termos difusos, enquanto que o Mamdani fornece esse elemento. Como o artigo está escrito para os traders difusos, será usado o Mamdani. Mas isso não implica que o modelo de Sugeno não seja adequado para algumas tarefas específicas: sempre é possível e necessário experimentar, baseando-se na compreensão básica da lógica difusa.

#include <Math\Fuzzy\MamdaniFuzzySystem.mqh>
CMamdaniFuzzySystem *OurFuzzy=new CMamdaniFuzzySystem();

A biblioteca está inclusa, uma referência à classe Mamdani é declarada. Isso é tudo o que é necessário para começar.

Agora, consideremos os principais estágios de construção da inferência difusa. Ele ocupa um lugar central em sistemas de modelagem difusa. O processo da inferência difusa é um procedimento específico ou um algoritmo para a obtenção de conclusões difusas com base em premissas difusas usando as operações básicas da lógica difusa.

Existem 7 estágios de construção da inferência difusa.

  • Determinação da estrutura do sistema de inferência difusa.

O número de entradas e saídas, bem como as funções de pertinência, são definidas no estágio de projeto. No nosso caso, haverá 4 entradas, 1 saída e cada uma delas terá 3 funções de pertinência.

  • Formação da base de regras do sistema de inferência difusa.

Durante o processo de desenvolvimento, nós criamos as regras personalizadas para a inferência difusa, com base no nosso julgamento especializado do sistema de negociação.

  • Fuzzificação das variáveis ​​de entrada.

Define a correspondência entre o valor numérico da variável de entrada do sistema de inferência difusa e o valor da função de pertinência do termo correspondente da variável linguística.

  • Agregação

Procedimento para determinar o grau de verdade das condições para cada regra do sistema de inferência difusa.

  • Ativação

O processo de encontrar o grau de verdade de cada uma das proposições elementares (subcláusulas) que constituem os consequentes dos núcleos de todas as regras de produção difusa.

  • Acumulação

O processo de encontrar uma função de pertinência para cada uma das variáveis ​​linguísticas de saída.

  • Defuzzificação
O processo de transição da função de pertinência da variável linguística de saída para o seu valor nítido (numérico). O valor de saída estará no intervalo de 0 a 1.

Note que somente os pontos 1 e 2 precisam ser realizados, todos os outros serão feitos pelo sistema sem intervenção. Aqueles interessados ​​nas sutilezas da operação da lógica difusa em todas as etapas podem encontrar mais detalhes aqui.

Determinação da estrutura do sistema de inferência difusa

Vamos continuar com a criação do modelo. Defina os objetos de três entradas e uma saída, bem como os objetos auxiliares do dicionário para facilitar o trabalho com a lógica:

CFuzzyVariable *firstInput=new CFuzzyVariable("rsi1",0.0,1.0);
CFuzzyVariable *secondInput=new CFuzzyVariable("rsi2",0.0,1.0);
CFuzzyVariable *thirdInput=new CFuzzyVariable("rsi3",0.0,1.0);
CFuzzyVariable *fuzzyOut=new CFuzzyVariable("out",0.0,1.0);

CDictionary_Obj_Double *firstTerm=new CDictionary_Obj_Double;
CDictionary_Obj_Double *secondTerm=new CDictionary_Obj_Double;
CDictionary_Obj_Double *thirdTerm=new CDictionary_Obj_Double;
CDictionary_Obj_Double *Output;

Três RSI com diferentes períodos serão utilizados como entradas. Como o oscilador RSI está sempre na faixa de 0-100, é necessário criar uma variável para ele com a mesma dimensão. Mas por conveniência, os valores dos indicadores serão normalizados para um intervalo de 0-1. Basta ter em mente que a variável criada deve ter uma dimensão igual à dimensão do vetor de entrada, ou seja, deve conter todos os valores. Um intervalo de 0 a 1 também está definido na saída.

De acordo com o ponto 1 da criação da lógica difusa, também é necessário definir e configurar as funções de pertinência. Isso será feito no manipulador de eventos da OnInit():

firstInput.Terms().Add(new CFuzzyTerm("buy", new CZ_ShapedMembershipFunction(0.0,0.6)));
firstInput.Terms().Add(new CFuzzyTerm("neutral", new CNormalMembershipFunction(0.5, 0.2)));
firstInput.Terms().Add(new CFuzzyTerm("sell", new CS_ShapedMembershipFunction(0.4,1.0)));
OurFuzzy.Input().Add(firstInput);
   
secondInput.Terms().Add(new CFuzzyTerm("buy", new CZ_ShapedMembershipFunction(0.0,0.6)));
secondInput.Terms().Add(new CFuzzyTerm("neutral", new CNormalMembershipFunction(0.5, 0.2)));
secondInput.Terms().Add(new CFuzzyTerm("sell", new CS_ShapedMembershipFunction(0.4,1.0)));
OurFuzzy.Input().Add(secondInput);
   
thirdInput.Terms().Add(new CFuzzyTerm("buy", new CZ_ShapedMembershipFunction(0.0,0.6)));
thirdInput.Terms().Add(new CFuzzyTerm("neutral", new CNormalMembershipFunction(0.5, 0.2)));
thirdInput.Terms().Add(new CFuzzyTerm("sell", new CS_ShapedMembershipFunction(0.4,1.0)));
OurFuzzy.Input().Add(thirdInput);
   
fuzzyOut.Terms().Add(new CFuzzyTerm("buy", new CZ_ShapedMembershipFunction(0.0,0.6)));
fuzzyOut.Terms().Add(new CFuzzyTerm("neutral", new CNormalMembershipFunction(Gposition, Gsigma)));
fuzzyOut.Terms().Add(new CFuzzyTerm("sell", new CS_ShapedMembershipFunction(0.4,1.0)));
OurFuzzy.Output().Add(fuzzyOut);

Agora, vamos ver qual é a função membro e qual propósito ela serve.

Três termos foram criados para cada variável de entrada (e uma saída): "buy", "neutral", "sell", cada um com sua própria função de pertinência. Em outras palavras, os valores dos osciladores agora podem ser divididos em 3 grupos difusos, e cada grupo pode ter um intervalo de valores usando a função de pertinência. Falando na linguagem da lógica difusa, 4 conjuntos de termos foram criados, cada um dos quais possuem 3 termos. Para ilustrar o que foi dito acima, nós vamos escrever um script simples que pode ser usado para a visualização dos termos e suas funções de pertinência:

//+------------------------------------------------------------------+ 
//|                                      Our MembershipFunctions.mq5 | 
//|                        Copyright 2016, MetaQuotes Software Corp. | 
//|                                             https://www.mql5.com | 
//+------------------------------------------------------------------+ 
#include <Math\Fuzzy\membershipfunction.mqh> 
#include <Graphics\Graphic.mqh> 
//--- Cria funções de pertinência 
CZ_ShapedMembershipFunction func2(0.0, 0.6);
CNormalMembershipFunction func1(0.5, 0.2); 
CS_ShapedMembershipFunction func3(0.4, 1.0);

//--- Criação wrappers para funções de pertinência 
double NormalMembershipFunction1(double x) { return(func1.GetValue(x)); } 
double ZShapedMembershipFunction(double x) { return(func2.GetValue(x)); }
double SShapedMembershipFunction(double x) { return(func3.GetValue(x)); }
 
//+------------------------------------------------------------------+ 
//| Script da função de início do programa                           | 
//+------------------------------------------------------------------+ 
void OnStart() 
  { 
//--- cria o gráfico 
   CGraphic graphic; 
   if(!graphic.Create(0,"Our MembershipFunctions",0,30,30,780,380)) 
     { 
      graphic.Attach(0,"Our MembershipFunctions"); 
     } 
   graphic.HistoryNameWidth(70); 
   graphic.BackgroundMain("Our MembershipFunctions"); 
   graphic.BackgroundMainSize(16); 
//--- cria a curva 
   graphic.CurveAdd(NormalMembershipFunction1,0.0,1.0,0.01,CURVE_LINES,"[0.5, 0.2]"); 
   graphic.CurveAdd(ZShapedMembershipFunction,0.0,1.0,0.01,CURVE_LINES,"[0.0, 0.6]"); 
   graphic.CurveAdd(SShapedMembershipFunction,0.0,1.0,0.01,CURVE_LINES,"[0.4, 1.0]"); 
//--- define as propriedades do eixo X 
   graphic.XAxis().AutoScale(false); 
   graphic.XAxis().Min(0.0); 
   graphic.XAxis().Max(1.0); 
   graphic.XAxis().DefaultStep(0.1); 
//--- define as propriedades do eixo Y 
   graphic.YAxis().AutoScale(false); 
   graphic.YAxis().Min(0.0); 
   graphic.YAxis().Max(1.1); 
   graphic.YAxis().DefaultStep(0.1); 
//--- plota 
   graphic.CurvePlotAll(); 
   graphic.Update(); 
  }

Executamos o script no gráfico:

Figura 1. A função de pertinência.

Essas funções de associação foram selecionadas, porque elas possuem apenas 2 parâmetros de entrada otimizados (isso será feito mais tarde, durante a fase de teste do sistema). Eles também descrevem bem as posições extrema e central do sistema. Você pode aplicar qualquer função de pertinência dos disponíveis na biblioteca Fuzzy.

Vamos adotar uma regra de que os valores extremos do oscilador indicam uma mudança futura em sua direção e, consequentemente, uma iminente inversão da tendência. Portanto, o oscilador que se aproxima de zero sugere um possível início de crescimento. O movimento do oscilador para a marca de 0.5 é acompanhado por uma diminuição gradual no CZ_ShapedMembershipFunction ou termo "Buy zone". Ao mesmo tempo, a incerteza em CNormalMembershipFunction da "Neutral zone"crescerá, que eventualmente será substituído por um aumento da CS_ShapedMembershipFunction ou "Zona de venda" à medida que o oscilador se aproxima de 1. O mesmo princípio é usado em todas as entradas e saídas, que verificam se os valores do indicador pertencem a uma determinada zona com limites difusos.

Não há restrições sobre o número de funções de associação para cada variável. Você pode definir 5, 7, 15 funções em vez de três, mas, é claro que, dentro dos limites do senso comum e em nome da lógica difusa.

Formação da base de regras do sistema de inferência difusa.

Nesta fase, nós adicionamos uma base de conhecimento ao sistema a ser usado ao tomar decisões difusas.

   rule1 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is buy) and (rsi3 is buy) then (out is buy)");
   rule2 = OurFuzzy.ParseRule("if (rsi1 is sell) and (rsi2 is sell) and (rsi3 is sell) then (out is sell)");
   rule3 = OurFuzzy.ParseRule("if (rsi1 is neutral) and (rsi2 is neutral) and (rsi3 is neutral) then (out is neutral)"); 
   
   rule4 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is sell) and (rsi3 is buy) then (out is neutral)");
   rule5 = OurFuzzy.ParseRule("if (rsi1 is sell) and (rsi2 is sell) and (rsi3 is buy) then (out is neutral)");
   rule6 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is buy) and (rsi3 is sell) then (out is neutral)"); 
   
   rule7 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is buy) and (rsi3 is neutral) then (out is buy)");
   rule8 = OurFuzzy.ParseRule("if (rsi1 is sell) and (rsi2 is sell) and (rsi3 is neutral) then (out is sell)");
   rule9 = OurFuzzy.ParseRule("if (rsi1 is buy) and (rsi2 is neutral) and (rsi3 is buy) then (out is buy)");
   rule10 = OurFuzzy.ParseRule("if (rsi1 is sell) and (rsi2 is neutral) and (rsi3 is sell) then (out is sell)");
   rule11 = OurFuzzy.ParseRule("if (rsi1 is neutral) and (rsi2 is buy) and (rsi3 is buy) then (out is buy)");
   rule12 = OurFuzzy.ParseRule("if (rsi1 is neutral) and (rsi2 is sell) and (rsi3 is sell) then (out is sell)");

   OurFuzzy.Rules().Add(rule1);
   OurFuzzy.Rules().Add(rule2);
   OurFuzzy.Rules().Add(rule3);
   OurFuzzy.Rules().Add(rule4);
   OurFuzzy.Rules().Add(rule5);
   OurFuzzy.Rules().Add(rule6);
   OurFuzzy.Rules().Add(rule7);
   OurFuzzy.Rules().Add(rule8);
   OurFuzzy.Rules().Add(rule9);
   OurFuzzy.Rules().Add(rule10);
   OurFuzzy.Rules().Add(rule11);
   OurFuzzy.Rules().Add(rule12);


Pelo menos uma condição lógica deve ser adicionada à base de conhecimento: ela é considerada incompleta se pelo menos um termo não estiver envolvido nas operações lógicas. Pode haver uma quantidade indefinida de condições lógicas.

O exemplo fornecido estabelece 12 condições lógicas, que influenciam a inferência difusa quando encontrada. Assim, todos os termos participam de operações lógicas. Por padrão, todas as operações lógicas recebem os mesmos coeficientes de peso iguais a 1. Eles não serão alterados neste exemplo.

Se todos os 3 indicadores estiverem dentro da área difusa para comprar, um sinal de compra difuso será gerado. O mesmo se aplica aos sinais de venda e neutros. (regras 1-3)

Se 2 indicadores mostram compra e um mostra venda, o valor de saída será neutro, ou seja, incerto. (regras 4-6)

Se 2 indicadores mostrarem compra ou venda e um é neutro, então a compra ou venda é atribuída ao valor de saída. (regras 7-12)

Obviamente, esta não é a única variante para criar uma base de regras, você pode experimentar. Esta base de regras baseia-se apenas no meu julgamento "expert" e na visão de como o sistema deve funcionar.

Obtenção de um valor de saída nítido após a defuzzicação

Resta calcular o modelo e obter o resultado como um valor de 0 a 1. Valores próximos de 0 indicam um forte sinal de compra, aqueles próximos de 0.5 são neutros e valores próximos de 1 significam um forte sinal de venda.

double CalculateMamdani()

{
 CopyBuffer(hnd1,0,0,1,arr1);
 NormalizeArrays(arr1);
   
 CopyBuffer(hnd2,0,0,1,arr2);
 NormalizeArrays(arr2);
    
 CopyBuffer(hnd3,0,0,1,arr3);
 NormalizeArrays(arr3);
     
 firstTerm.SetAll(firstInput,arr1[0]);
 secondTerm.SetAll(secondInput,arr2[0]);
 thirdTerm.SetAll(thirdInput,arr2[0]);
       
 Inputs.Clear(); 
 Inputs.Add(firstTerm);
 Inputs.Add(secondTerm);
 Inputs.Add(thirdTerm);
      
 CList *FuzzResult=OurFuzzy.Calculate(Inputs);
 Output=FuzzResult.GetNodeAtIndex(0);
 double res = Output.Value();
 delete FuzzResult;

 return(res);
}

Esta função obtém os valores de três osciladores RSI com diferentes períodos, normaliza-os para um intervalo de 0 a 1 (os valores podem ser simplesmente divididos por 100), atualiza a lista com objetos do dicionário Fuzzy (os valores dos indicadores mais recentes), envia-os para os cálculos, cria uma lista para a variável de saída e leva o resultado na variável 'res'.

Adição de funções de serviço e otimização/testes do sistema resultante

Uma vez que a aprendizagem de máquina ou, pelo menos, o básico também está sendo considerado, alguns parâmetros serão movidos para as entradas e otimizados.

input string Fuzzy_Setings;        //Configurações de otimização difusa
input double Gsigma = 0.5;         //sigma De 0.05 para 0.5 com passe de 0.05
input double Gposition=0.5;        //posição De 0.0 para 1.0 com passo de 0.1
input double MinNeutralSignal=0.4; //MinNeutralSignal de 0.3 para 0.5 com passo de 0.1
input double MaxNeutralSignal=0.6; //MaxNeutralSignal de 0.5 para 0.7 com passo de 0.1

Os parâmetros da função pertinente Gaussiana serão submetidos a otimização na saída da lógica difusa. Ele terá seu centro ao longo do eixo X deslocado (parâmetro Gposition), mudança do sigma (estreitar e comprimir o sino, parâmetro Gsigma). Isso dará um ajuste fino ao sistema no caso dos sinais RSI para compra e venda serem assimétricos.

Além disso, otimize as condições para abertura de operações: o valor mínimo de um sinal neutro e o valor máximo (as novas posições não serão abertas no intervalo entre esses valores, pois o sinal não está definido).

O processamento de um sinal na saída da lógica difusa é mostrado a seguir:

void OnTick()
  {
//---
   if(!isNewBar())
     {  
      return;
     }
     
   double TradeSignal=CalculateMamdani(); 
   
   if(CountOrders(0)!=0 || CountOrders(1)!=0)                                           // se houver posições abertas
      {
       for(int b=OrdersTotal()-1; b>=0; b--)
         {
          if(OrderSelect(b,SELECT_BY_POS)==true)
           {
            if(OrderSymbol()==_Symbol && OrderMagicNumber()==OrderMagic)
             {
              if(OrderType()==OP_BUY && TradeSignal>=MinNeutralSignal)                  // uma ordem de compra é selecionada e o sinal de negociação é maior que o limite esquerdo do sinal neutro
               {                                                                        // ou seja, existe um sinal neutro ou um sinal de venda
                if(OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),0,Red))       // então fecha a posição de compra
                 {
                  if(TradeSignal>MaxNeutralSignal)                     // se a ordem é fechada e existe um sinal de venda (excede o limite direito do sinal neutro), abra imediatamente uma posição de venda
                  {
                   lots = LotsOptimized(); 
                   if(OrderSend(Symbol(),OP_SELL,lots,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0,0,NULL,OrderMagic,Red)){
                     };
                  }
                 }
               }
               if(OrderType()==OP_SELL && TradeSignal<=MaxNeutralSignal)                 // uma ordem de venda é selecionada....///.... o mesmo que posições de compra, mas todas as condições são espelhadas
               {
                if(OrderClose(OrderTicket(),OrderLots(),OrderClosePrice(),0,Red))
                 {
                  if(TradeSignal<MinNeutralSignal)
                  {
                   lots = LotsOptimized(); 
                   if(OrderSend(Symbol(),OP_BUY,lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0,0,NULL,OrderMagic,Green)){
                    };
                  }
                 }
               }
             }
            }
          }
         return;
        }
                 // se não houver posições, abre as posições de acordo com os sinais
   lots = LotsOptimized(); 
   if(TradeSignal<MinNeutralSignal && CheckMoneyForTrade(_Symbol,lots,ORDER_TYPE_BUY))
     { 
      if(OrderSend(Symbol(),OP_BUY,lots,SymbolInfoDouble(_Symbol,SYMBOL_ASK),0,0,0,NULL,OrderMagic,Green)){
       };
     }
   else if(TradeSignal>MaxNeutralSignal && CheckMoneyForTrade(_Symbol,lots,ORDER_TYPE_SELL))
     {
      if(OrderSend(Symbol(),OP_SELL,lots,SymbolInfoDouble(_Symbol,SYMBOL_BID),0,0,0,NULL,OrderMagic,Red)){
       };
     }
   return;
     
  }


Os cálculos serão realizados na nova barra para acelerar a demonstração. Você é livre para personalizar a lógica a seu critério, por exemplo, negociar em todos os ticks através da remoção da verificação para uma nova barra.

Se houver posições abertas e o sinal contradizer a posição atual ou não estiver definido, feche a posição. Se houver uma condição para abrir uma posição oposta, abra-a.

Este sistema não utiliza stop loss, pois não são reversões de posição, e o encerramento/reabertura de posição é baseado nos sinais.

O Expert Advisor usa a biblioteca MT4Orders para facilitar o trabalho com ordens e tornar o código facilmente conversível em MQL4.

Processo de teste

O sistema é otimizado usando as configurações mostradas nas capturas de tela, no período M15, no período de 8 meses, com base nos Preços de abertura, usando o algoritmo baseado em genética rápida e o critério de otimização Balance + max Profit.



Seleciona o melhor resultado da otimização:

Compara com os resultados de teste do modelo rígido:

As funções de associação resultantes na saída, após a otimização (as entradas permanecem inalteradas uma vez que não foram otimizadas):

Antes das mudanças:

Depois:


Otimização do sistema com as mesmas configurações, mas no tempo gráfico M5:

Compara com os resultados de teste do modelo rígido:

As funções de associação resultantes na saída, após a otimização (as entradas permanecem inalteradas uma vez que não foram otimizadas):

Antes das mudanças:

Depois:

Em ambos os casos, o deslocamento Gaussiano (zona neutra) em direção às compras e o número de posições compradas prevalecem sobre o número de posições vendidas. Isso significa que os sinais de compra e venda se tornaram assimétricos neste segmento específico do histórico, que não poderia ser descoberto sem essa experiência. É possível que o sistema que consiste em três RSI foi na zona de sobrevenda (área 1) mais frequente que na zona de sobrecompra (área 0) e a otimização Gaussiana ajudou a suavizar esse desequilíbrio. Quanto à saída mais nítida, é consistentemente difícil imaginar por que tal configuração de saída contribuiu para a melhoria dos resultados do sistema de negociação, pois o processo de defuzzificação usando o método do centro de gravidade, em conjunto com todo o mapeamento de entradas para conjuntos difusos, já é um sistema complexo por si só.

O sistema mostrou-se bastante estável durante 8 meses, embora apenas 4 parâmetros foram otimizados. E eles podem ser facilmente reduzidos a dois (Gsigma e Gposition), uma vez que os 2 restantes tiveram pouco impacto no resultado e estão sempre próximos de 0.5. Isto é assumido como um resultado satisfatório para um sistema experimental, visando mostrar como o número de parâmetros otimizados pode ser reduzido através da introdução de um elemento de lógica difusa no sistema de negociação. Em contraste, teria sido necessário criar numerosos critérios de otimização para regras rígidas, o que aumentaria a complexidade do desenvolvimento do sistema e o número de parâmetros otimizados.

Também deve ser observado que este ainda é um exemplo muito grosseiro de construir um sistema de negociação baseado na lógica difusa, pois usa uma estratégia primitiva baseada em RSI sem sequer usar o stop loss. No entanto, isso deve ser suficiente para entender a aplicabilidade da lógica difusa à criação de sistemas de negociação.

Conclusão

A lógica difusa permite uma rápida criação de sistemas com regras difusas que são muito simples de otimizar. Ao mesmo tempo, o complexo processo de seleção dos parâmetros do sistema de negociação passa pela otimização genética, liberando o desenvolvedor da rotina de busca de uma estratégia comercial, desenvolvendo e algoritimizando inúmeras regras do sistema de negociação. Juntamente com outros métodos de aprendizagem de máquina (por exemplo, redes neurais), esta abordagem permite alcançar resultados impressionantes. Isso reduz a chance de superação e a dimensão dos dados de entrada (3 indicadores RSI com diferentes períodos reduzidos a um único sinal, que descreve a situação do mercado de forma mais completa e mais generalizada do que cada indicador por conta própria).

Se você ainda tem problemas para entender como funciona a lógica difusa, pergunte-se sobre como você pensa, quais os termos que você opera e quais as bases de regras em que sua tomada de decisão se baseia.

Aqui está um exemplo de reforço. Por exemplo, você tem 3 desejos: ir a uma festa, assistir a um filme em casa ou salvar o mundo. O termo "assistir a um filme em casa" tem o maior peso, porque você já está em casa e nenhum esforço adicional é necessário. Ir para uma festa é viável se alguém o convidar e buscar você, mas, como ainda não aconteceu, as mudanças de andamento são médias. E, finalmente, para salvar o mundo, você precisa mobilizar todas as suas habilidades sobrenaturais, colocar uma fantasia de superman e lutar contra um monstro alienígena. É improvável que você decida fazer isso hoje e não deixar para amanhã, então as chances são escassas.

A inferência difusa será algo assim: Provavelmente vou ficar em casa, e talvez eu vá à festa, mas definitivamente não vou salvar o mundo hoje. Após a defuzzificação, nossas chances podem ser avaliadas em uma escala de 0 a 10, onde 0 é "ficar em casa", 5 é "ir para a festa", 10 é "lutar contra um monstro". Obviamente, o resultado nítido ficaria na faixa de 0 a 3, ou seja, é mais provável que você fique em casa. O mesmo princípio é usado no sistema de negociação apresentado: ele compara os valores de três indicadores e usa as condições lógicas para determinar a opção mais preferível no momento atual: comprar, vender ou não fazer nada.

Possíveis maneiras de melhorar este exemplo (para auto-estudo):

  • Aumentando o número de entradas e condições lógicas. Isso aumenta a capacidade do sistema e torna-o mais adaptável ao mercado.
  • Otimização não apenas da saída Gaussiana, mas também de todas as funções de associação das entradas e saídas.
  • Otimização da regra base.
  • Otimização dos pesos das expressões lógicas.
  • Criação de um círculo de vários modelos difusos responsáveis ​​por diferentes aspectos do sistema de negociação.
  • Utilização da inferência difusa como preditores ("características") e/ou variáveis ​​alvo para as redes neurais.

Se houver interesse suficiente no artigo, e eu receber feedback suficiente, eu poderia considerar a possibilidade de escrever um novo artigo dedicado à combinação da lógica difusa e uma rede neural.

Abaixo estão os códigos-fonte dos experts e um script de teste para as funções de associação. Para que o EA compile e funcione corretamente, é necessário baixar a biblioteca MT4Orders e a biblioteca Fuzzy atualizada.

Traduzido do russo pela MetaQuotes Software Corp.
Artigo original: https://www.mql5.com/ru/articles/3795

Arbitragem triangular Arbitragem triangular

O artigo é dedicado ao popular método de negociação arbitragem triangular. O assunto é analisado em muitos detalhes, são discutidos os aspectos positivos e negativos da estratégia, é desenvolvido o código pronto para usar do expert.

Uma Nova Abordagem para a Interpretação da Divergência Clássica e Oculta Uma Nova Abordagem para a Interpretação da Divergência Clássica e Oculta

O artigo considera o método clássico para a construção de divergências e fornece um método adicional de interpretação de divergência. Uma estratégia de negociação foi desenvolvida com base neste novo método de interpretação. Esta estratégia também é descrita no artigo.

Comparação de diferentes tipos de médias móveis durante a negociação Comparação de diferentes tipos de médias móveis durante a negociação

São examinados 7 tipos de médias móveis (MA), é criada uma estratégia de negociação para trabalhar com eles. É levado a cabo o teste e comparação de diferentes MA numa mesma estratégia de negociação, são apresentadas as características comparativas quanto a eficiência de cada média móvel.

Uso do filtro de Kalman na previsão da tendência Uso do filtro de Kalman na previsão da tendência

Para o sucesso na negociação, quase sempre são necessários indicadores, cujo objetivo é a separação entre o movimento principal do preço e as flutuações ruidosas. Neste artigo, é examinado um dos filtros digitais mais promissores, o filtro de Kalman. Além disso, são descritos tanto sua construção como uso na prática.