
Filtragem de acordo com o histórico
MetaTrader 4
—
Sistemas de negociação
| 18 fevereiro 2016, 15:24
Introdução
Há vários filtros diferentes: valores de indicadores, volatilidade do mercado, tempo, dia da semana. Todos eles podem ser usados para fazer a seleção de negociações desvantajosas. É bastante fácil adicionar um filtro do tipo a um expert advisor: basta adicionar mais uma condição antes do bloco de abertura.
Mas o que deve ser feito caso você queira usar o histórico do EA como um filtro? Se você desligar o seu sistema de negociação após várias negociações mal sucedidas, você não terá um histórico mais tarde, e portanto não haverá nada a ser analisado. Para resolver este problema, nós precisamos ensinar o expert advisor a realizar negociações virtualmente, ou seja, simular a abertura, modificação e fechamento de negociações sem realizar negociações reais.
É disso que trata este artigo.
Estratégia experimental
Para a implementação do nosso sistema nós faremos algumas modificações no arquivo CrossMACD_DeLuxe.mq4 do expert advisor:
- durante a abertura/modificação/fechamento de cada posição, mudanças serão escritas em uma matriz de posições virtuais;
- adição de monitoramento de atuação do StopLoss e TakeProfit de posições virtuais;
- adição de um critério de filtragem: uma condição na qual negociações reais não serão abertas.
Eu tentarei descrever cada passo da modificação do EA com maior quantidade de detalhes possível. Caso você não esteja interessado nisso, você pode fazer o download do expert advisor pronto e pular para a parte "O jogo não vale a candle?".
Contabilização de posições virtuais
Então, um sinal para abrir uma posição surgiu. Os parâmetros StopLoss e TakeProfit são calculados, e tudo está pronto para a chamada da função OrderSend(). Precisamente neste momento nós abrimos a negociação virtual - basta salvar todos os parâmetros necessários nas variáveis apropriadas:
void OpenBuy() { int _GetLastError = 0; double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel; _OpenPriceLevel = NormalizeDouble(Ask, Digits); if(StopLoss > 0) _StopLossLevel = NormalizeDouble(_OpenPriceLevel - StopLoss*Point, Digits); else _StopLossLevel = 0.0; if(TakeProfit > 0) _TakeProfitLevel = NormalizeDouble(_OpenPriceLevel + TakeProfit*Point, Digits); else _TakeProfitLevel = 0.0; //---- open the virtual position virtOrderSend(OP_BUY, _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel); if(OrderSend(Symbol(), OP_BUY, 0.1, _OpenPriceLevel, 3, _StopLossLevel, _TakeProfitLevel, "CrossMACD", _MagicNumber, 0, Green) < 0) { _GetLastError = GetLastError(); Alert("Error OrderSend № ", _GetLastError); return(-1); } } //---- Save parameters of the opened position in main variables void virtualOrderSend(int type, double openprice, double stoploss, double takeprofit) { virtTicket = 1; virtType = type; virtOpenPrice = openprice; virtStopLoss = stoploss; virtTakeProfit = takeprofit; }
Nós podemos usar apenas cinco variáveis:
int virtTicket = 0; // determines, if there is an open virtual position int virtType = 0; // position type double virtOpenPrice = 0.0; // position opening price double virtStopLoss = 0.0; // position StopLoss double virtTakeProfit = 0.0; // position TakeProfit
Nós não precisamos de outras características para obter a salvação da nossa tarefa. Se você quiser ampliar a funcionalidade deste exemplo, basta adicionar a quantidade necessária de variáveis.
Para rastrear o fechamento e a modificação de posições, nós precisamos tomar mais medidas. Copie o bloco de controle de posições abertas, que está no expert advisor, e transforme as características do pedido em características virtuais:
int start() { // skipped... //+------------------------------------------------------------------+ //| Control block of "virtual" positions | //+------------------------------------------------------------------+ if(virtTicket > 0) { //---- if BUY-position is open, if(virtType == OP_BUY) { //---- if MACD crossed 0-line downwards, if(NormalizeDouble(MACD_1 + CloseLuft*Point*0.1, Digits + 1) <= 0.0) { //---- close position virtOrderClose(Bid); } //---- if the signal did not change, accompany the position by // TrailingStop else { if(TrailingStop > 0) { if(NormalizeDouble(Bid - virtOpenPrice, Digits ) > 0.0) { if(NormalizeDouble( Bid - TrailingStop*Point - virtStopLoss, Digits) > 0.0 || virtStopLoss < Point) { virtStopLoss = Bid - TrailingStop*Point; } } } } } //---- if SELL position is open if(virtType == OP_SELL) { //---- if MACD crossed 0-line upwards, if(NormalizeDouble(MACD_1 - CloseLuft*Point*0.1, Digits + 1 ) >= 0.0) { //---- close the position virtOrderClose(Ask); } //---- if the signal did not change, accompany the position by // TrailingStop else { if ( TrailingStop > 0 ) { if(NormalizeDouble( virtOpenPrice - Ask, Digits ) > 0.0 ) { if(NormalizeDouble( virtStopLoss - ( Ask + TrailingStop*Point ), Digits ) > 0.0 || virtStopLoss <= Point ) { virtStopLoss = Ask + TrailingStop*Point; } } } } } } // skipped... return(0); } //---- virtual position closing function void virtOrderClose(double closeprice) { //---- Save the parameters of the closed position in the array ArrayResize(virtClosedOrders, virtClosedOrdersCount + 1); virtClosedOrders[virtClosedOrdersCount][0] = virtType; virtClosedOrders[virtClosedOrdersCount][1] = virtOpenPrice; virtClosedOrders[virtClosedOrdersCount][2] = virtStopLoss; virtClosedOrders[virtClosedOrdersCount][3] = virtTakeProfit; virtClosedOrders[virtClosedOrdersCount][4] = closeprice; virtClosedOrdersCount ++; //---- clear variables virtTicket = 0; virtType = 0; virtOpenPrice = 0.0; virtStopLoss = 0.0; virtTakeProfit = 0.0; }
A modificação se transformou na simples atribuição de um novo valor à variável virtStopLoss. E o fechamento é bastante difícil: todas as características do pedido fechado são salvas em uma matriz. Mais tarde, todo o histórico virtual será salvo nela. A partir dela, nós iremos obter as informações sobre as posições fechadas para tomar uma decisão a respeito da abertura de uma nova posição.
Agora nós precisamos processar o fechamento da posição no StopLoss e no TakeProfit. Para isso, adicione várias strings ao bloco de controle criado.
if(virtType == OP_BUY) { //---- check, whether SL was not activated if(virtStopLoss > 0.0 && NormalizeDouble(virtStopLoss - Bid, Digits ) >= 0.0) { virtOrderClose(virtStopLoss); } //---- check, whether TPL was not activated if(virtTakeProfit > 0.0 && NormalizeDouble( Bid - virtTakeProfit, Digits ) >= 0.0) { virtOrderClose(virtTakeProfit); } }
Agora o nosso histórico virtual está pronto e nós podemos adicionar um critério de filtragem.
O que é "bom" e o que é "ruim"?
Nós precisamos proibir a abertura de posições após uma determinada condição ser implementada. Mas que condição devemos escolher? Várias negociações desvantajosas em sequência, a ativação do StopLoss ou a redução do lucro médio de várias negociações recentes. Certamente é difícil responder a essa pergunta. Cada opção possui as suas vantagens e desvantagens.
Para verificar a eficiência de cada condição, vamos tentar escrever o código de todas as três e testá-las no histórico.
extern int TradeFiltrVariant = 0; //---- Function of checking the necessity of the real trading bool virtCheckCondition() { int pos, check_pos = 2; double last_profit = 0.0, pre_last_profit = 0.0; //---- depending on the value of TradeFiltrVariant: switch(TradeFiltrVariant) { //---- 1: prohibit real trading, if 2 last deals are losing case 1: { //---- if the virtual history contains enough orders, if(virtClosedOrdersCount >= check_pos) { for(pos = 1; pos check_pos; pos ++) { //---- if the deal is profitable, return true if((virtClosedOrders[virtClosedOrdersCount-pos][0] == 0 && virtClosedOrders[virtClosedOrdersCount-pos][4] - virtClosedOrders[virtClosedOrdersCount-pos][1] >= 0.0) || (virtClosedOrders[virtClosedOrdersCount-pos][0] == 1 && virtClosedOrders[virtClosedOrdersCount-pos][1] - virtClosedOrders[virtClosedOrdersCount-pos][4] >= 0.0)) { return(true); } } } return(false); } //---- 2: prohibit real trading if the last position was closed // by StopLoss case 2: { //---- if the virtual history contains enough orders, if(virtClosedOrdersCount > 0) { //---- if the closing price of the last order is equal to StopLoss, if(virtClosedOrders[virtClosedOrdersCount-1][2] - virtClosedOrders[virtClosedOrdersCount-1][4] < Point && virtClosedOrders[virtClosedOrdersCount-1][4] - virtClosedOrders[virtClosedOrdersCount-1][2] < Point) { return(false); } } return(true); } //---- 3: prohibit real trading, if the profit of the last position //---- is lower than that of the last but one position (or loss is higher) case 3: { if(virtClosedOrdersCount >= 2) { if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0) { last_profit = virtClosedOrders[virtClosedOrdersCount-1][4] - virtClosedOrders[virtClosedOrdersCount-1][1]; } else { last_profit = virtClosedOrders[virtClosedOrdersCount-1][1] - virtClosedOrders[virtClosedOrdersCount-1][4]; } if(virtClosedOrders[virtClosedOrdersCount-2][0] == 0) { pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][4] - virtClosedOrders[virtClosedOrdersCount-2][1]; } else { pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][1] - virtClosedOrders[virtClosedOrdersCount-2][4]; } if(pre_last_profit - last_profit > 0.0) { return(false); } } return(true); } //---- by default the filter is off, i.e. positions will be always opened in reality default: return(true); } return(true); } void OpenBuy() { int _GetLastError = 0; double _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel; _OpenPriceLevel = NormalizeDouble(Ask, Digits); if(StopLoss > 0) { _StopLossLevel = NormalizeDouble(_OpenPriceLevel - StopLoss*Point, Digits); } else { _StopLossLevel = 0.0; } if(TakeProfit > 0) { _TakeProfitLevel = NormalizeDouble(_OpenPriceLevel + TakeProfit*Point, Digits); } else { _TakeProfitLevel = 0.0; } //---- open a virtual position virtOrderSend(OP_BUY, _OpenPriceLevel, _StopLossLevel, _TakeProfitLevel); //---- if virtual positions filter prohibits trading, exit if(virtCheckCondition() == false) { return(0); } if(OrderSend( Symbol(), OP_BUY, 0.1, _OpenPriceLevel, 3, _StopLossLevel, _TakeProfitLevel, "CrossMACD", _MagicNumber, 0, Green) < 0 ) { _GetLastError = GetLastError(); Alert("Error OrderSend № ", _GetLastError); return(-1); } }
Agora nós temos uma variável externa, TradeFiltrVariant. Ela é responsável pela escolha do critério de filtragem:
extern int TradeFiltrVariant = 0; //---- 0: filter is off, i.e. position is always opened in reality //---- 1: prohibit real trading, if 2 last positions are losing //---- 2: prohibit real trading, if the last position closed by StopLoss //---- 3: prohibit real trading, if the profit of the last position is lower, //---- than that of the last but one psition (or loss is higher)
Agora teste o expert advisors com filtros diferentes e compare os resultados.
O jogo não vale a candle?
Eu escolhi os seguintes parâmetros para o teste:
Símbolo: Período GBPUSD
: H4, 01.01.2005 - 01.01.2006
Modo de modelagem: todos os ticks (qualidade de modelagem 90%, cotas do HistoryCenter)
Parâmetros do EA:
StopLoss: 50
TakeProfit: 0 (desativado)
TrailingStop: 0 (desativado)
FastEMAPeriod: 12
SlowEMAPeriod: 26
OpenLuft: 10
CloseLuft: 0
A seguinte tabela mostra a dependência dos resultados em relação ao filtro usado:
TradeFiltrVariant | Lucro/perda total | Total de negociações | Negociações lucrativas | Negociações desvantajosas |
---|---|---|---|---|
0 | 1678,75 |
41 | 9 (22%) |
32 (78%) |
1 | 105,65 | 20 |
2 (10%) |
18 (90%) |
2 | -550,20 | 11 | 0 (0%) |
11 (100%) |
3 | 1225,13 | 28 | 7 (25%) |
21 (75%) |
Como você pode ver, a teoria a respeito da utilidade do filtro não foi comprovada. Além disso, os resultados das negociações com o filtro foram mais baixos do que aqueles das negociações sem o filtro. A única exceção foi a terceira opção - a taxa de negociações lucrativas foi mais alta (25 % contra 22%), mas o lucro total foi menor com todas as opções.
O que deu errado? Provavelmente, o critério de filtragem estava errado. Vamos tentar transformar esses três filtros nos filtros opostos, ou seja, fechar negociações reais se:
- as duas últimas negociações tiverem sido lucrativas;
- a última posição for lucrativa (nós não temos um análogo ao StopLoss, pois o TakeProfit está desativado);
- O lucro da última posição for maior do que o da penúltima.
Para não restringir o expert advisor, simplesmente adicione mais três valores de TradeFiltrVariant - 4, 5 e 6:
//---- 4: prohibit real trading, if two last trades are profitable //---- 5: prohibit real trading, if the last position is profitable //---- 6: prohibit real trading, if the profit of the last position is higher, //---- than that of the last but one position (or loss is lower) //---- 4: prohibit real trading, if two last trades are profitable case 4: { if(virtClosedOrdersCount >= check_pos) { for(pos = 1; pos check_pos; pos ++) { //---- if the trade is losing, return true if((virtClosedOrders[virtClosedOrdersCount-pos][0] == 0 && virtClosedOrders[virtClosedOrdersCount-pos][1] - virtClosedOrders[virtClosedOrdersCount-pos][4] > 0.0) || (virtClosedOrders[virtClosedOrdersCount-pos][0] == 1 && virtClosedOrders[virtClosedOrdersCount-pos][4] - virtClosedOrders[virtClosedOrdersCount-pos][1] > 0.0)) { return(true); } } } return(false); } //---- 5: prohibit real trading, if the last position is profitable case 5: { if(virtClosedOrdersCount >= 1) { if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0) { last_profit = virtClosedOrders[virtClosedOrdersCount-1][4] - virtClosedOrders[virtClosedOrdersCount-1][1]; } else { last_profit = virtClosedOrders[virtClosedOrdersCount-1][1] - virtClosedOrders[virtClosedOrdersCount-1][4]; } if(last_profit > 0.0) { return(false); } } return(true); } //---- 6: prohibit real trading, if the profit of the last position is higher, //---- than that of the last but one position (or loss is lower) case 6: { if(virtClosedOrdersCount >= 2) { if(virtClosedOrders[virtClosedOrdersCount-1][0] == 0) { last_profit = virtClosedOrders[virtClosedOrdersCount-1][4] - virtClosedOrders[virtClosedOrdersCount-1][1]; } else { last_profit = virtClosedOrders[virtClosedOrdersCount-1][1] - virtClosedOrders[virtClosedOrdersCount-1][4]; } if(virtClosedOrders[virtClosedOrdersCount-2][0] == 0) { pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][4] - virtClosedOrders[virtClosedOrdersCount-2][1]; } else { pre_last_profit = virtClosedOrders[virtClosedOrdersCount-2][1] - virtClosedOrders[virtClosedOrdersCount-2][4]; } if(last_profit - pre_last_profit > 0.0) { return(false); } } return(true); }
Agora vamos testar essas três novas opções e adicioná-las à nossa tabela:
AdaptVariant | Lucro/perda total | Total de negociações | Transações lucrativas | Negociações desvantajosas |
---|---|---|---|---|
0 | 1678,75 |
41 | 9 (22%) |
32 (78%) |
1 | 105,65 | 20 | 2 (10%) |
18 (90%) |
2 | -550,20 | 11 | 0 (0%) |
11 (100%) |
3 | 1225,13 | 28 | 7 (25%) |
21 (75%) |
4 |
1779,24 |
39 | 9 (23%) | 30 (77%) |
5 |
2178,95 |
31 |
9 (29%) |
22 (71%) |
6 |
602,32 |
24 |
5 (21%) |
19 (79%) |
A sexta opção filtrou metade das negociações, tanto as lucrativas quanto as desvantajosas. A quarta excluiu duas negociações desvantajosas, aumentado o lucro total em $100,49.
E a melhor opção foi aquela que proíbe negociações após toda negociação lucrativa: ela filtrou 10 negociações desvantajosas e nenhuma lucrativa.
Portanto, há esperança. Até mesmo uma estratégia tão simples e popular pode ser melhorada!
Conclusão
Eu acho que este tipo de filtro não é suficiente para uma melhoria real do sistema. Pesquisas muito mais profundas devem ser realizadas, e novas conclusões devem ser feitas.
Os filtros descritos podem ser tornados mais complexos e absolutamente diferentes para cada estratégia. A sua eficiência depende diretamente da troca entre as posições lucrativas e desvantajosas.
Este artigo se limita à questão da filtragem. Mas eu espero que ele lhe inspire a ir além.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1441
Arquivos anexados |
CrossMACD_TradeFiltr.mq4
(20.61 KB)
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
Ir para discussão

A mudança de cotação é um grande problema para muitos expert advisors, especialmente para aqueles que possuem condições bastante sensíveis para a entrada/saída de uma negociação. Neste artigo, é oferecida uma forma de verificar a estabilidade de mudança de cotações de um EA.

O artigo trata da detecção e indicação dos níveis de apoio/resistência no programa MetaTrader 4. O indicador conveniente e universal é baseado em um algoritmo simples. O artigo lida com um tópico bastante útil: a criação de um indicador simples, capaz de exibir os resultados de diferentes períodos de tempo em um espaço de trabalho.

Neste artigo escreveremos uma biblioteca simples para a construção de diagramas 3D e sua exibição posterior no Microsoft Excel. Usaremos as opções padrão do MQL4 para preparar e exportar os dados ao arquivo *.csv.

Este artigo descreve o processo de criação de um script simples para a detecção dos níveis de apoio/resistência. Ele foi escrito para iniciantes, então você encontrará uma explicação detalhada de cada estágio do processo. Contudo, apesar do script ser bastante simples, o artigo também será útil para traders avançados e usuários da plataforma MetaTrader 4. Ele contém exemplos da exportação de dados para o formato tabular, da importação da tabela para o Microsoft Excel, e do delineamento de gráficos para a realização de uma análise mais detalhada.

Você está perdendo oportunidades de negociação:
- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Registro
Login
Você concorda com a política do site e com os termos de uso
Se você não tem uma conta, por favor registre-se