
Contratos futuros contínuos em MetaTrader 5
Introdução
O trader não pode criar seus próprios gráficos em MetaTrader 5, pois somente podem ser construídos com os ativos da corretora. O trader necessita de um produto sintético - os contratos futuros contínuos. O problema é que somente a corretora pode fazer emendas de contratos e somente a corretora decide se vai ligar os contratos futuros sobre o símbolo dado.
Felizmente, o histórico dos futuros fechados está sempre disponível no terminal. Use este histórico para emendar os contratos futuros no terminal.
Convenções:
- Todos os dados, desenhos e imagens no artigo baseiam-se no contrato futuro real do índice de Ações Ucraniana.
- Seções de código substituídos ou adicionados no artigo serão marcado com cores.Por exemplo:
//+------------------------------------------------------------------+ //| This is an example | //| of the edited code | //+------------------------------------------------------------------+
O primeiro problema: sobrepor dados
Os contratos futuros próximos são negociados com datas sobrepostas,
isso significa que o futuro é colocado em negociação enquanto outros futuros ainda tem dois meses para serem fechados.
Fig. 1. Datas se sobrepõem em contratos de futuros
A figura mostra que 09.16.2013 é a data de início da negociação do contrato futuro UX-3.14, embora o contrato futuro UX-12.13 ainda está em aberto.
O segundo problema: escolher a forma de emendar
Existem dois métodos de emendar:
- A adição simples – quando a data de circulação do instrumento em vigor expira e o próximo instrumento é aberto em outra barra. Os preços durante a adição simples no gráfico irão coincidir com seus valores do histórico, mas ao mesmo tempo sempre haverá gaps de preços nos lugares emendados, ou seja, o gráfico não será suave.
Fig. 2. Emendando. Adição simples
- adição com deslocamento: o instrumento em vigor tem entre 5 a 10 dias antes de ser fechado, então começamos a substituir essas 5-10 barras com as próximas barras do instrumento. O intervalo de 5-10 barras é chamado de período de transição. Os preços durante a adição com deslocamento irão mostrar valores errados (que não correspondem ao atual instrumento), mas o gráfico será mais suave em comparação com o método de adição simples.
Fig. 3. Emendando. Adição com deslocamento
Configurações no terminal
O contrato futuro deve ser colocado em ordem descendente:
Fig. 4. Observação do mercado
Escrevendo um indicador
O indicador padrão deve ser colocado na pasta "indicators" no seguinte caminho de diretório: terminal_data_folder\MQL5\Indicators. Criar a pasta Synthetics em MyIndicators (que você vai abrir na pasta \Indicators). Permitirá que você salve o espaço na pasta \Indicators na Biblioteca Padrão (Standard Library) e facilitará o lançamento sincronizado dos indicadores na seção Armazenamento MQL5. O caminho final da pastas fica assim: terminal_data_folder\MQL5\Indicators\MyIndicators\Synthetics.
Na pasta Synthetics criamos um novo arquivo:
Fig. 5. O novo arquivo criado do indicador
Defina o novo tipo de arquivo - "Indicador Personalizado":
Fig. 6. Defina o novo tipo de arquivo - "indicador personalizado"
Pressione o botão "Avançar" e abra a janela "propriedades gerais do indicador personalizado". Digite o nome do indicador - "SYNT", adicione dois parâmetros O primeiro parâmetro "Number_futures_gluing" (Número de futuros para colagem) determina o número de instrumentos a serem conectados. Note que 2 é o menor valor possível de "Number_futures_for_gluing". A segunda opção "Gluing type" (Tipo de colagem) determina o tipo de emenda no indicador padrão - "simple addition"(adição simples):
Fig. 7. Os parâmetros do indicador personalizado
Preste atenção para a opção "Gluing type": a emenda pode ser "simples adição" ou "adição com deslocamento". Nesta fase você não pode adicionar na lista os dois tipos de emenda. É por isso que deixamos a "simples adição" como padrão. Durante o processo de escrever o código do indicador "SYNT", mais tarde será ativada a opção para ver a lista dropdown (suspensa) com os tipos de emendas.
Na janela seguinte, selecione os handlers (manipuladores) dos eventos do indicador:
Fig. 8. Os handlers de eventos do indicador
Note que a função OnTimer() será usada pelo indicador "SYNT". A principal funcionalidade do indicador situa-se no OnTimer() . O indicador pode ser anexado ao gráfico do ativo com o trade finalizado (este ativo não incluirá o evento OnCalculate) ou com o gráfico do ativo com um trade em andamento.
Pressione o botão "Avançar" e nas "Propriedades gerais do programa indicador personalizado" assinale "Indicador em janela separada":
Fig. 9. opção "indicador em janela separada"
Pressione o botão "Concluído" e você vai ver o modelo do indicador "SYNT".
Organizar a lista dropdown (suspensa)
Para ver os tipos de emendas como uma lista suspensa você precisa declarar a enumeração ENUM_GLUING_TYPE nas opções dos indicadores.
Declarar enumeração na área global no início do bloco dos parâmetros de entrada:
#property indicator_separate_window //+------------------------------------------------------------------+ //| Splicing types enumeration | //+------------------------------------------------------------------+ enum ENUM_GLUING_TYPE { simple_addition, // simple addition||simple addition addition_with_shift // addition with shift||addition with shift }; //--- input parameters || input parameters input ENUM_GLUING_TYPE gluing_type=simple_addition; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+
Agora você pode verificar como a lista suspensa é exibida.
Você deve compilar o arquivo do indicador (F7). Agora, depois de ter anexado o indicador, você pode ver as opções da lista suspensa:
Fig. 10. Agora você tem a
lista dropdown nos parâmetros
Adicionar a descrição do indicador que será exibido na guia "Geral" quando for anexado ao gráfico pela primeira vez ou quando as suas propriedades forem alteradas:
#property version "1.00" //+------------------------------------------------------------------+ //| version "1.00": The timer history swapping | //+------------------------------------------------------------------+ #property description "Indicator for several futures splicing." #property description "Is drawn in the latest futures window" #property description "Uses N first symbols for drawing" #property description "which were taken from the \"Market review\"." #property indicator_separate_window
O método de construção do indicador - DRAW_COLOR_CANDLES - candles coloridos.
Você precisa de 4 buffers para o indicador e um buffer para o índice de armazenamento de cor. O estilo de linha do indicador - STYLE_SOLID - linha contínua. Mostrar tudo no código do indicador:
#property description "taken from the \"Market review\"." //--- indicator settings || indicator settings #property indicator_separate_window #property indicator_buffers 5 #property indicator_plots 1 //--- plot Bars || bars plotting #property indicator_label1 "SYNT" #property indicator_type1 DRAW_COLOR_CANDLES #property indicator_style1 STYLE_SOLID #property indicator_width1 1 //+------------------------------------------------------------------+ //| enumeration of splicing methods | //+------------------------------------------------------------------+
Digite o parâmetro de entrada "number_futures_gluing" - o número de instrumentos necessários para a construção. O valor padrão do "number_futures_gluing" é igual a 2:
//--- input parameters || input parameters input int numder_futures_gluing=2; input ENUM_GLUING_TYPE gluing_type=simple_addition;
Declarar os 4 buffers para o indicador, um buffer para o índice de armazenamento de cor e um array auxiliar LoadHistory[].
#property indicator_style1 STYLE_SOLID #property indicator_width1 1 //--- indicator buffers || indicator buffers double OpenBuffer[]; double HighBuffer[]; double LowBuffer[]; double CloseBuffer[]; double ColorCandlesColors[]; double LoadHistory[]; //+------------------------------------------------------------------+ //| enumeration of splicing methods | //+------------------------------------------------------------------+
Anexar os buffers do indicador aos arrays dinâmicos de uma dimensão, definir a indexação dos buffers como nas timeseries:
//--- indicator buffers mapping //--- indicator buffers mapping SetIndexBuffer(0,OpenBuffer,INDICATOR_DATA); SetIndexBuffer(1,HighBuffer,INDICATOR_DATA); SetIndexBuffer(2,LowBuffer,INDICATOR_DATA); SetIndexBuffer(3,CloseBuffer,INDICATOR_DATA); SetIndexBuffer(4,ColorCandlesColors,INDICATOR_COLOR_INDEX); SetIndexBuffer(5,LoadHistory,INDICATOR_CALCULATIONS); //--- set buffer indexing as timeseries //--- set buffer indexing as in timeseries ArraySetAsSeries(OpenBuffer,true); ArraySetAsSeries(HighBuffer,true); ArraySetAsSeries(LowBuffer,true); ArraySetAsSeries(CloseBuffer,true); ArraySetAsSeries(ColorCandlesColors,true); //--- return(INIT_SUCCEEDED);
Para exibir o nome das séries do indicador ("Open", "High", "Low" e "Close") na "janela de dados" é necessário a variável s_symbol:
input int numder_futures_gluing=2; input ENUM_GLUING_TYPE gluing_type=simple_addition; //--- symbol name string s_symbol; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+
Para ativar o indicador você precisa da variável shft_array e duas flags, good_history e indicator_rendered:
input ENUM_GLUING_TYPE gluing_type=simple_addition; //--- symbol name string s_symbol; int shift_array=0; bool good_history=false; //history is not prepared||history not prepared bool indicator_rendered=false; // indicator is not drawn //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+
Em seguida, configure o indicador e conecte o buffer do índice de cor para a cor escolhida:
ArraySetAsSeries(CloseBuffer,true); ArraySetAsSeries(ColorCandlesColors,true); //--- set accuracy || accuracy of the indicator values IndicatorSetInteger(INDICATOR_DIGITS,0); //--- set drawing line empty value || empty value of the drawing line PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0); //--- set labels for the line || displayed name in the DataWindow PlotIndexSetString(0,PLOT_LABEL,s_symbol+" Open;"+s_symbol+" High;"+s_symbol+" Low;"+s_symbol+" Close"); IndicatorSetString(INDICATOR_SHORTNAME,"SYNT"); //--- set number of colors in color buffer || number of colors in the buffer PlotIndexSetInteger(0,PLOT_COLOR_INDEXES,9); //--- set line color || set the line color PlotIndexSetInteger(0,PLOT_LINE_COLOR,0,clrBlue); PlotIndexSetInteger(0,PLOT_LINE_COLOR,1,clrOrange); PlotIndexSetInteger(0,PLOT_LINE_COLOR,2,clrRed); PlotIndexSetInteger(0,PLOT_LINE_COLOR,3,clrGreen); PlotIndexSetInteger(0,PLOT_LINE_COLOR,4,clrPink); PlotIndexSetInteger(0,PLOT_LINE_COLOR,5,clrIndigo); PlotIndexSetInteger(0,PLOT_LINE_COLOR,6,clrPaleVioletRed); PlotIndexSetInteger(0,PLOT_LINE_COLOR,7,clrDarkViolet); PlotIndexSetInteger(0,PLOT_LINE_COLOR,8,clrDimGray); //--- return(INIT_SUCCEEDED);
Adicionar a inicialização do temporizador com intervalos de 3 segundos e o gerador de números aleatórios na função OnInit() :
PlotIndexSetInteger(0,PLOT_LINE_COLOR,7,clrDarkViolet); PlotIndexSetInteger(0,PLOT_LINE_COLOR,8,clrDimGray); //--- EventSetTimer(3); //--- random number generator initializor MathSrand(GetTickCount()); //--- return(INIT_SUCCEEDED);
É necessário pelo menos dois símbolos (ativos) para processar a emenda.
Verifique o número de instrumentos (ativos) para emendar na função OnCalculate():
const long &tick_volume[], const long &volume[], const int &spread[]) { //--- checking the number of instruments || checking the number of instruments if(numder_futures_gluing<=1) { //--- create the message line string comm=StringFormat("For the indicator choose not less than %d symbols",numder_futures_gluing); //--- display the message in comment in the chart main window Comment(comm); return(0); } //--- return value of prev_calculated for next call return(rates_total);
Depois de ter verificado o número de ativos para a emenda, verificar se o indicador já foi desenhado. Se o indicador foi desenhado, então você pode sair do OnCalculate() :
Comment(comm); return(0); } if(indicator_rendered==true) return(rates_total); //--- return value of prev_calculated for next call return(rates_total);
Como o indicador "SYNT" é usado principalmente para analisar a tendência de desenvolvimento de barras diárias, considero que não há necessidade de proceder novos cálculos em cada tick. Não haverá cálculos do indicador "SYNT" a cada tick.
Você precisa calcular o indicador apenas nos seguintes casos:
- Se o indicador foi lançado pela primeira vez;
- se o histórico foi alterado (por exemplo, se houveram adições).
if(indicator_rendered==true) return(rates_total); //--- if calculations were started the first time //--- or if we need to calculate the indicator for two or more bars (changes in history) //--- remember, that the "0" bar - is the left-most if(prev_calculated==0 || rates_total>prev_calculated+1) { } //--- return value of prev_calculated for next call return(rates_total);
Inicialização forçada dos buffers do indicador
Os buffers do indicador "SYNT" são conectados nos arrays dinâmicos
Quando o indicador é lançado pela primeira vez, os buffers são inicializados forçadamente. Prosseguir com a inicialização no OnCalculate(). Por que você precisa conduzir-lo no OnCalculate() e não no OnInit? A explicação está na figura abaixo:
Fig. 11. A inicialização do array no OnCalculate()
Como você pode ver na Fig.11, o evento OnCalculate() irá ocorrer em qualquer caso, enquanto que o OnInit() é ativado quando você faz a atualização do gráfico por meio do comando "Update". Portanto, a inicialização dos arrays serão conduzidas no OnCalculate():
//--- remember, that the "0" bar - is the left-most if(prev_calculated==0 || rates_total>prev_calculated+1) { //--- arrays initialization ArrayInitialize(OpenBuffer,0); ArrayInitialize(HighBuffer,0); ArrayInitialize(LowBuffer,0); ArrayInitialize(CloseBuffer,0); } //--- return value of prev_calculated for next call return(rates_total);
A função ArrayInitialize() inicializa o buffer do indicador Neste caso a inicialização mostra zeros.
Se você tentar inicializar o indicador de buffer pelo EMPTY_VALUE , você não poderá emendar os indicadores sobre o "SYNT".
Algoritmo da Adição simples
Fig. 12. Algoritmo da Adição simples
As datas na imagem são o início e fim da circulação dos contratos futuros UX-9.13, UX-12.13 e UX-3.14. Estes dados são apresentados na tabela:
Símbolo (Ativo) | Início da circulação | Final da circulação |
---|---|---|
UX-9.13 | 03.15.2013 | 09.16.2013 |
UX-12.13 | 06.17.2013 | 12.16.2013 |
UX-3.14 | 09.16.2013 | 03.17.2014 |
Na Fig. 10, data 12.25.2013 - é uma data do calendário real. O ativo UX-3.14 ainda é válido.
O método de emenda "Adição Simples" será implementado na função SimpleAddition:
//+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- } //+------------------------------------------------------------------+ //| Simple addition | //| Simple addition. Add in the indicator array | //| sibmUP symbol | //+------------------------------------------------------------------+ bool SimpleAddition(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color) { } //+------------------------------------------------------------------+
simbUP é o contrato futuro de alta, simbDOWN é contrato futuro de baixa, ambos estão localizados na janela de "Análise do mercado". Color - cor usada para desenhar os contratos futuros.
O código completo da função SimpleAddition() é descrita abaixo:
//+------------------------------------------------------------------+ //| Simple addition | //| Simple addition. Add in the indicator array | //| sibmUP symbol | //+------------------------------------------------------------------+ bool SimpleAddition(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color)////// { datetime expiration_time_UP; // simbUP symbol expiration date datetime expiration_time_DOWN; // simbDOWN expiration date expiration_time_UP=int(SymbolInfoInteger(simbUP,SYMBOL_EXPIRATION_TIME)); if(expiration_time_UP>TimeLocal()) { expiration_time_UP=TimeLocal(); } if(simbDOWN!="") { expiration_time_DOWN=int(SymbolInfoInteger(simbDOWN,SYMBOL_EXPIRATION_TIME)); } else { expiration_time_DOWN=int(SymbolInfoInteger(simbUP,SYMBOL_START_TIME)); } //--- Open, High, Low and Close prices will be copied in the rates[] array MqlRates rates[]; ArraySetAsSeries(rates,true); int copied=0; //--- copied number copied=CopyRates(simbUP,period,expiration_time_DOWN,expiration_time_UP,rates); if(copied>0) { for(int j=shift_array;j<shift_array+copied;j++) { //--- write prices in buffers OpenBuffer[j]=rates[j-shift_array].open; HighBuffer[j]=rates[j-shift_array].high; LowBuffer[j]=rates[j-shift_array].low; CloseBuffer[j]=rates[j-shift_array].close; ColorCandlesColors[j]=Color; } shift_array=shift_array+copied; indicator_rendered=true; ChartRedraw(); } else { Print("Unable to get the symbol history data",simbUP); indicator_rendered=false; return(false); } //--- Simple addition end return(true); } //+------------------------------------------------------------------+
Algoritmo da Adição com deslocamento
Fig. 13. Algoritmo da emenda Adição com deslocamento
Este algoritmo de emenda em comparação com a adição simples, começa 10 dias antes fechar o ativo. O método de emenda "Adição com deslocamento" é processado na função AdditionWithShift():
//--- Simple addition end return(true); } //+------------------------------------------------------------------+ //| Addition With Shift | //| Addition with Shift. Add in the indicator array only | //| sibmUP symbol | //+------------------------------------------------------------------+ bool AdditionWithShift(string simbUP,string simbDOWN,ENUM_TIMEFRAMES period,int Color) { //--- return(true); } //+------------------------------------------------------------------+
A diferença entre as funções AdditionWithShift() e SimpleAddition() está em duas linhas - vai subtrair 10 dias a contar das datas:
. . . expiration_time_UP=int(SymbolInfoInteger(simbUP,SYMBOL_EXPIRATION_TIME))-86400*10; . . . expiration_time_DOWN=int(SymbolInfoInteger(simbDOWN,SYMBOL_EXPIRATION_TIME))-86400*10; . . .
Devido à pequena diferença de códigos, não vou mostrar o código completo da função AdditionWithShift(), você pode encontrar o código no arquivo do indicador no artigo.
Apesar das diferenças entre as funções AdditionWithShift() e SimpleAddition(), é melhor você não uni-las para fazer uma função universal (no caso de novas mudanças no algoritmo ou, por exemplo, executando testes).
Histórico do pré-carregamento dos ativos
A função CheckLoadHistory() copia todo o histórico dos símbolos no buffer auxiliar tmp_rates.
Se o processo de cópia for bem sucedido, o valor true é atribuído a flag good_history, significando que se pode começar a desenhar o indicador:
//--- Addition With Shift end return(true); } //+------------------------------------------------------------------+ //| Request to receive all history from a trade server | //| Request to recieve all history from a trade server | //+------------------------------------------------------------------+ bool CheckLoadHistory(string symbol,ENUM_TIMEFRAMES period) { MqlRates tmp_rates[]; // the Open, High, Low and Close prices will be copied in the rates[]array datetime start_time; // start time of the instrument trades datetime expiration_time; // expiration time of the instrument trade start_time=int(SymbolInfoInteger(symbol,SYMBOL_START_TIME)); expiration_time=int(SymbolInfoInteger(symbol,SYMBOL_EXPIRATION_TIME)); if(CopyRates(symbol,period,start_time,expiration_time,tmp_rates)>0) { good_history=true; } else { good_history=false; } //--- return(true); } //+------------------------------------------------------------------+
Você pode copiar todo o histórico dos contratos futuros, onde o histórico copiado não ocupará muito espaço.
OnTimer - a função principal do indicador
Agora você tem o código para dois métodos de emendas e o código para carregar o histórico de modo que você pode mudar a função OnTimer():
//+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { if(indicator_rendered==true) return; if(good_history==true) { int t=0; // color || color int number; switch(gluing_type) { case simple_addition: for(int n=0;n<numder_futures_gluing;n++) { //--- get the random number number=MathRand(); //--- get the color index as the modulo t=number%(PlotIndexGetInteger(0,PLOT_COLOR_INDEXES)-1); SimpleAddition(SymbolName(n,true),SymbolName(n+1,true),PERIOD_D1,t); } break; case addition_with_shift: for(int n=0;n<numder_futures_gluing;n++) { //--- get random number number=MathRand(); //--- get the color index as the modulo t=number%(PlotIndexGetInteger(0,PLOT_COLOR_INDEXES)-1); AdditionWithShift(SymbolName(n,true),SymbolName(n+1,true),PERIOD_D1,t); } break; } } else { for(int n=0;n<numder_futures_gluing;n++) { CheckLoadHistory(SymbolName(n,true),PERIOD_D1); } } } //+------------------------------------------------------------------+
O indicador esta concluído. Você pode compilar e anexar ao gráfico. É melhor escolher o ativo com o negócio fechado e definir o período em H1.
Saída inicial do indicador "SYNT"
Depois de ter anexado os dois modelos de indicadores "SYNT" de diferentes métodos de emenda ao gráfico, você pode comparar esses métodos:
Fig. 14. Comparando os dois métodos de emendas de contratos futuros
A possibilidade de juntar indicadores (padrão e personalizado)
Indicadores personalizados podem ser emendados com a primeira chamada OnCalculate e o indicador "SYNT":
int OnCalculate (const int rates_total, // size of the array price[] const int prev_calculated, // calculated bars during the previous call const int begin, // tangible data starting point const double& price[] // calculation array );
Na janela "Navegador" abra a lista "Indicadores personalizados". Em seguida, abra a lista de "Exemplos", escolha e coloque o indicador "SYNT" no ativo. Na aba "Parâmetros", escolha "Dados do indicador anterior" na lista suspensa.
Aqui está a lista com os indicadores que você pode emendar no indicador "SYNT" que será executado sem erros.
- AMA (Adaptive Moving Average);
- BB (Bollinger Bands);
- Custom Moving Average;
- DEMA (Double Exponential Moving Average);
- FrAMA (Fractal Adaptive Moving Average);
- TEMA (Triple Exponential Moving Average).
O indicador "SYNT" emendando três contratos futuros com o indicador Custom Moving Average anexado:
Fig. 15. Um exemplo de três ativos emendados
Conclusão
É mais fácil analisar o comportamento dos ativos mais antigos no gráfico aberto dentro do timeframe diário. Embora o número de indicadores técnicos é restrito, este método ajuda a traçar o comportamento dos preços nos contratos futuros contínuos.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/802
Aviso: Todos os direitos sobre esses materiais pertencem à MetaQuotes Ltd. É proibida a reimpressão total ou parcial.
This article was written by a user of the site and reflects their personal views. MetaQuotes Ltd is not responsible for the accuracy of the information presented, nor for any consequences resulting from the use of the solutions, strategies or recommendations described.





- Aplicativos de negociação gratuitos
- 8 000+ sinais para cópia
- Notícias econômicas para análise dos mercados financeiros
Você concorda com a política do site e com os termos de uso
É um bom artigo. Não tenho a pretensão de ser original. Mas, aqui estão minhas considerações: o início e a circulação dos futuros são sempre voláteis e não refletem o quadro real de onde os volumes subjacentes estão ocorrendo.
Não sei até que ponto isso é possível. Mas vou dizer o seguinte. E se definirmos um intervalo para cada contrato futuro em datas (em que ocorrem negociações normais) e otimizarmos essas seções como um todo?
Ou seja, é possível testar um gráfico em um teste e depois mudar para outro e assim por diante?
Se você estiver se perguntando: "Posso testar a colagem no testador de estratégia?" - a resposta é não. Ou seja, não funcionará de maneira simples, porque a colagem é um indicador personalizado.
Está claro que ele não funcionará com futuros colados. Eu quis dizer que nos livros e fóruns eles escrevem qual forma de colagem reflete melhor o movimento real. No livro de Robert Pardo, esse tópico foi bem discutido.
A ideia é que você possa definir um intervalo de datas para cada futuro e testar tudo em um número de anos como um todo.
Com futuros colados, fica claro que isso não funcionará. Eu quis dizer que em livros e fóruns eles escrevem qual forma de colagem reflete melhor o movimento real. No livro de Robert Pardo, esse tópico foi bem discutido.
A ideia é que você pode definir um intervalo de datas para cada futuro e testar tudo por vários anos como um todo.
Isso é chamado de "tipo de colagem". Especificamente, o artigo considera dois tipos de colagem - "Adição simples" e "Adição com deslocamento".
Já existem ferramentas de castum disponíveis há algum tempo.
Talvez haja um produto que gere e atualize a cola também? Ninguém o conhece?
Essa ferramenta poderia ser usada para testar e executar Expert Advisors (atribuindo o símbolo correto para negociação, é claro).