Gráficos "sem buracos"
1.Motivação
"No MT 4, apenas tais barras são desenhadas, dentro das quais pelo menos uma mudança de preço ocorreu. Se nenhuma mudança de preço ocorreu dentro de um minuto, um espaço de uma barra ocorrerá no gráfico com período de um minuto".
Os desenvolvedores optaram deliberadamente por essa forma de desenho de gráficos pois a maioria dos traders que usam o produto prefere gráficos que contenham apenas preços existentes. De todo modo, há usuários que gostam de gráficos contínuos. Eles preferem que a barra seja desenhada mesmo que o seu preço seja igual ao preço de fechamento da barra anterior. Portanto, não há lacunas na escala de tempo do gráfico, e 100 barras sempre correspondem a 100 minutos no gráfico de um minuto. Estes dados podem ser diferentes na realização atual. Por exemplo, 100 minutos podem "caber" em 98 barras caso entre eles haja 2 minutos nos quais nenhuma cota chegou.
Por sorte, todas as ferramentas necessárias estão disponíveis no MQL4 para nos auxiliar a desenhar este tipo de gráfico de modo independente.
2.Realização
Primeiramente, vamos dividir esta tarefa em dois estágios:
-
processamento de dados do histórico
-
atualização da barra mais recente
No primeiro estágio, nós criamos um novo arquivo de histórico com o prefixo "ALL" antes do nome do símbolo ("ALL" significa que "todas as barras" estão aqui) e escrevemos nele o histórico com as barras adicionadas.
Um problema semelhante é resolvido no script "period_converter" ("conversor de período") que é fornecido com o terminal do cliente MT4. O script gera um gráfico com um período não padrão. Nós usaremos esse exemplo para aprender a trabalhar com o arquivo de histórico.
Antes da criação de um programa, nós precisamos decidir que forma ele terá: Ele será um script, um indicador ou um expert? Indicadores são usados para exibir os conteúdos de uma matriz. Nós não precisamos disso no momento. Quanto a scripts e experts, a única diferença entre eles é que os scripts são deletados do gráfico imediatamente após a sua operação ser completada. Isso nos é conveniente no momento, então nós vamos produzir um script agora.
Isso é o que vamos obter como resultado (AllMinutes_Step1.mq4):
#property show_inputs //---- Enable/disable drawing bars on holidays //---- If == true, holidays will remain unfilled //---- If == false, holidays will be filled out with bars O=H=L=C extern bool SkipWeekEnd=true; int start() { int HistoryHandle=-1,pre_time,now_time,_PeriodSec; double now_close,now_open,now_low,now_high,now_volume,pre_close; int _GetLastError=0,cnt_copy=0,cnt_add=0; int temp[13]; //---- remember the chart symbol and period string _Symbol=Symbol(); int _Period= Period(); _PeriodSec = _Period * 60; //---- open file, in which we will write the history string file_name=StringConcatenate("ALL",_Symbol,_Period,".hst"); HistoryHandle=FileOpenHistory(file_name,FILE_BIN|FILE_WRITE); if(HistoryHandle<0) { _GetLastError=GetLastError(); Alert("FileOpenHistory( \"",file_name,"\", FILE_BIN | FILE_WRITE )"," - Error #",_GetLastError); return(-1); } //---- Write the file heading FileWriteInteger(HistoryHandle,400,LONG_VALUE); FileWriteString(HistoryHandle,"Copyright © 2006, komposter",64); FileWriteString(HistoryHandle,"ALL"+_Symbol,12); FileWriteInteger(HistoryHandle,_Period,LONG_VALUE); FileWriteInteger(HistoryHandle,Digits,LONG_VALUE); FileWriteInteger(HistoryHandle,0,LONG_VALUE); //timesign FileWriteInteger(HistoryHandle,0,LONG_VALUE); //last_sync FileWriteArray(HistoryHandle,temp,0,13); //+-----------------------------------------------------------------+ //| Process the history //+-----------------------------------------------------------------+ int bars=Bars; pre_time=Time[bars-1]; for(int i=bars-1; i>=0; i--) { //---- Remember the bar parameters now_open=Open[i]; now_high=High[i]; now_low=Low[i]; now_close=Close[i]; now_volume=Volume[i]; now_time=Time[i]/_PeriodSec; now_time*=_PeriodSec; //---- if there are skipped bars, while(now_time>pre_time+_PeriodSec) { pre_time+=_PeriodSec; pre_time /= _PeriodSec; pre_time *= _PeriodSec; //---- if it is not the weekend, if(SkipWeekEnd) { if(TimeDayOfWeek(pre_time)<=0 || TimeDayOfWeek(pre_time)>5) { continue; } if(TimeDayOfWeek(pre_time)==5) { if( TimeHour(pre_time) == 23 || TimeHour(pre_time + _PeriodSec) == 23 ) { continue; } } } //---- write the skipped bar into the file FileWriteInteger(HistoryHandle,pre_time,LONG_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,0,DOUBLE_VALUE); FileFlush(HistoryHandle); cnt_add++; } //---- write the new bar into the file FileWriteInteger(HistoryHandle,now_time,LONG_VALUE); FileWriteDouble(HistoryHandle,now_open,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_low,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_high,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_volume,DOUBLE_VALUE); FileFlush(HistoryHandle); cnt_copy++; //---- remember the time value and the close price //---- of the recorded bar pre_close=now_close; pre_time=now_time/_PeriodSec; pre_time*=_PeriodSec; } //---- close the file FileClose(HistoryHandle); //---- display statistics Print("< - - - ",_Symbol,_Period,": there were ",cnt_copy, " bars, added ",cnt_add," bars - - - >"); Print("< - - - To view the results, open the chart \"ALL", _Symbol,_Period,"\" - - - >"); return(0); }
Recomenda-se prestar atenção à variável SkipWeekEnd. Caso o seu valor seja falso, os fins de semanas serão repletos com barras O=H=L=C (tracejadas).
Vamos verificar como o nosso script funciona. Para isso basta anexá-lo a um gráfico de um minuto GBPUSD:
Agora, vamos abrir o gráfico ALLGBPUSD1 no modo offline e compará-lo ao gráfico inicial:
Como você pode ver, alguns minutos pulados foram adicionados ao gráfico. Eles estão circulados em vermelho. Este é o resultado que nós esperávamos atingir, não é?
Como agora nós temos um gráfico com os buracos preenchidos, nós podemos atualizá-lo. As novas cotas serão mostradas nele, mas os novos buracos vão novamente permanecer não preenchidos.
O script "period_converter" pode novamente ser usado como um exemplo. Ele também pode resolver o problema da atualização dos gráficos. Nós faremos apenas uma mudança: Adicionar o bloco para preencher as barras puladas. Dado que o gráfico precisa ser atualizado a cada tick, vamos transferir o nosso código ao expert. Ele será inicializado sempre que uma nova cota chegar. Vamos colocar o código da primeira parte na função init(), pois esta parte só precisa ser executada uma vez, e a nova parte inteira do código será colocada na função start(), pois ela será usada a cada tick. Além disso, o fechamento de arquivos irá para a função deinit(), pois aquele é o lugar certo para ele.
Desse modo, o código do expert (AllMinutes_Step2.mq4) será o seguinte:
#include <WinUser32.mqh> //---- Enable/disable drawing of bars on holidays //---- If it is == true, the holidays will remain unfilled //---- If it is == false, the holidays will be filled with the O=H=L=C bars extern bool SkipWeekEnd=true; int HistoryHandle=-1,hwnd=0,last_fpos=0,pre_time,now_time; int _Period,_PeriodSec; double now_close,now_open,now_low,now_high,now_volume; double pre_close,pre_open,pre_low,pre_high,pre_volume; string _Symbol; int init() { int _GetLastError=0,cnt_copy=0,cnt_add=0; int temp[13]; //---- remember the chart symbol and period _Symbol=Symbol(); _Period=Period(); _PeriodSec=_Period*60; hwnd=0; //---- open the file to write the history in string file_name=StringConcatenate("ALL",_Symbol,_Period,".hst"); HistoryHandle=FileOpenHistory(file_name,FILE_BIN|FILE_WRITE); if(HistoryHandle<0) { _GetLastError=GetLastError(); Alert("FileOpenHistory( \"",file_name,"\", FILE_BIN | FILE_WRITE )"," - Error #",_GetLastError); return(-1); } //---- Write the file heading FileWriteInteger(HistoryHandle,400,LONG_VALUE); FileWriteString(HistoryHandle,"Copyright © 2006, komposter",64); FileWriteString(HistoryHandle,StringConcatenate("ALL",_Symbol), 12); FileWriteInteger(HistoryHandle,_Period,LONG_VALUE); FileWriteInteger(HistoryHandle,Digits,LONG_VALUE); FileWriteInteger(HistoryHandle,0,LONG_VALUE); //timesign FileWriteInteger(HistoryHandle,0,LONG_VALUE); //last_sync FileWriteArray(HistoryHandle,temp,0,13); //+-----------------------------------------------------------------+ //| Process the history //+-----------------------------------------------------------------+ int bars=Bars; pre_time=Time[bars-1]; for(int i=bars-1; i>=1; i--) { //---- Remember the bar parameters now_open=Open[i]; now_high=High[i]; now_low=Low[i]; now_close=Close[i]; now_volume=Volume[i]; now_time=Time[i]/_PeriodSec; now_time*=_PeriodSec; //---- if there are skipped bars, while(now_time>pre_time+_PeriodSec) { pre_time+=_PeriodSec; pre_time /= _PeriodSec; pre_time *= _PeriodSec; //---- if it isn't a weekend, if(SkipWeekEnd) { if(TimeDayOfWeek(pre_time)<=0 || TimeDayOfWeek(pre_time)>5) { continue; } if(TimeDayOfWeek(pre_time)==5) { if( TimeHour(pre_time) == 23 || TimeHour(pre_time + _PeriodSec) == 23 ) { continue; } } } //---- write the obtained bar into the file FileWriteInteger(HistoryHandle,pre_time,LONG_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,0,DOUBLE_VALUE); FileFlush(HistoryHandle); cnt_add++; } //---- write the new bar into the file FileWriteInteger(HistoryHandle,now_time,LONG_VALUE); FileWriteDouble(HistoryHandle,now_open,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_low,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_high,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_volume,DOUBLE_VALUE); FileFlush(HistoryHandle); cnt_copy++; //---- remember the time value and the close price of the recorded //---- bar pre_close=now_close; pre_time=now_time/_PeriodSec; pre_time*=_PeriodSec; } last_fpos=FileTell(HistoryHandle); //---- display statistics Print("< - - - ",_Symbol,_Period,": there were ",cnt_copy," bars, added ",cnt_add," bars - - - >"); Print("< - - - To view the results, open the chart \"ALL", _Symbol,_Period,"\" - - - >"); //---- call the start function for the 0th bar to be drawn immediately start(); return(0); } //---- int start() { //+---------------------------------------------------------------+ //| Process the incoming ticks //+---------------------------------------------------------------+ //---- place the "cursor" before the latest bar //---- (this must be done at all launches except for the first one) FileSeek(HistoryHandle,last_fpos,SEEK_SET); //---- Remember the bar parameters now_open=Open[0]; now_high=High[0]; now_low=Low[0]; now_close=Close[0]; now_volume=Volume[0]; now_time=Time[0]/_PeriodSec; now_time*=_PeriodSec; //---- if the bar has been formed, if(now_time>=pre_time+_PeriodSec) { //---- write the newly formed bar FileWriteInteger(HistoryHandle,pre_time,LONG_VALUE); FileWriteDouble(HistoryHandle,pre_open,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_low,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_high,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_volume,DOUBLE_VALUE); FileFlush(HistoryHandle); //---- remember the position in the file, before writing of the 0th bar last_fpos=FileTell(HistoryHandle); } //---- if the skipped bars have appeared, while(now_time>pre_time+_PeriodSec) { pre_time+=_PeriodSec; pre_time /= _PeriodSec; pre_time *= _PeriodSec; //---- if this is not weekend, if(SkipWeekEnd) { if(TimeDayOfWeek(pre_time)<=0 || TimeDayOfWeek(pre_time)>5) { continue; } if(TimeDayOfWeek(pre_time)==5) { if(TimeHour(pre_time)==23 || TimeHour(pre_time+_PeriodSec)==23) { continue; } } } //---- write the skipped bar into the file FileWriteInteger(HistoryHandle,pre_time,LONG_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,pre_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,0,DOUBLE_VALUE); FileFlush(HistoryHandle); //---- remember the position in the file, before writing of the 0th bar last_fpos=FileTell(HistoryHandle); } //---- write the current bar FileWriteInteger(HistoryHandle,now_time,LONG_VALUE); FileWriteDouble(HistoryHandle,now_open,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_low,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_high,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_close,DOUBLE_VALUE); FileWriteDouble(HistoryHandle,now_volume,DOUBLE_VALUE); FileFlush(HistoryHandle); //---- remember the parameters of the recorded bar pre_open=now_open; pre_high=now_high; pre_low=now_low; pre_close=now_close; pre_volume=now_volume; pre_time=now_time/_PeriodSec; pre_time*=_PeriodSec; //---- find the window the new quotes to be "sent" to if(hwnd==0) { hwnd = WindowHandle( StringConcatenate( "ALL", _Symbol ), _Period ); if( hwnd != 0 ) { Print("< - - - Chart ", "ALL"+_Symbol,_Period," has been found! - - - >"); } } //---- and, if successfully found, update it if(hwnd!=0) { PostMessageA(hwnd,WM_COMMAND,33324,0); } } //---- int deinit() { if(HistoryHandle>=0) { //---- close the file FileClose(HistoryHandle); HistoryHandle=-1; } return(0); }
Uma observação deve ser feita antes: A atualização do gráfico exige bastante do processador, pois o terminal carrega todas as barras escritas no arquivo. Caso haja muitas barras no arquivo, o terminal pode ficar bem mais lento. Isso depende principalmente do desempenho do PC no qual o terminal do cliente MT4 está instalado. De todo modo, os recursos não são inesgotáveis. Nós resolveremos este problema de modo simples: Simplesmente reduza a quantidade de barras exibida no gráfico para 10.000 ("Ferramentas" – "Opções" – "Gráficos", o parâmetro "máximo de barras no gráfico"). Vamos agora reiniciar o terminal e anexar o expert.
O expert "repara" imediatamente o histórico e fica à espera do surgimento do próximo tick. Após 2 minutos, o mesmo gráfico aparece do seguinte modo:
Como você pode ver, uma barra de um minuto foi adicionada ao gráfico superior, e a barra pulada foi adicionada ao gráfico inferior.
Isso significa que nós alcançamos o resultado desejado!
3.Dimensionamento
Um gráfico não representa problemas, é claro, mas o que nós devemos fazer caso surja a necessidade de abrir 10 gráficos sem barras puladas. A abertura de um gráfico adicional "temporário" para cada gráfico normal não seria a melhor solução. Serão consumidos recursos extras e, respectivamente, o trabalho se tornará menos confortável.
Vamos criar um expert que possa processar qualquer quantidade de gráficos. Esta será a solução adequada e econômica.
Portanto, nós teremos que modificar o nosso código para que ele possa trabalhar com vários gráficos simultaneamente:
-
adicione uma variável externa que auxilie a alterar a lista de gráficos,
-
substitua todas as variáveis por matrizes que possuam uma quantidade de elementos igual à quantidade de gráficos a serem processados,
-
coloque todo o código em um ciclo, no qual estes gráficos serão buscados, e
-
coloque o bloco de atualização no ciclo infinito, tornando-o assim independente da chegada de cotas. Caso símbolos diferentes estejam listados, o seu tempo de atualização também pode ser diferente.
É isso que devemos ter desenhado como resultado (AllMinutes.mq4):
#include <WinUser32.mqh> //---- The list of charts to be processed, separated by commas (",") extern string ChartList="EURUSD1,GBPUSD1"; //---- Enable/disable to draw bars at weekends //---- If it is == true, the weekends will remain unfilled //---- If it is == false, the weekends will be filled with the bars of O=H=L=C extern bool SkipWeekEnd=true; //---- Frequency of the charts updating, in milliseconds //---- the higher the value is, the less resources the expert //---- will use. extern int RefreshLuft=1000; int init() { start(); return(0); } int start() { int _GetLastError=0,cnt_copy=0,cnt_add=0,temp[13]; int Charts=0,pos=0,curchar=0,len=StringLen(ChartList); string cur_symbol="",cur_period="",file_name=""; string _Symbol[100]; int _Period[100],_PeriodSec[],_Bars[]; int HistoryHandle[],hwnd[],last_fpos[],pre_time[],now_time[]; double now_close[],now_open[],now_low[],now_high[],now_volume[]; double pre_close[],pre_open[],pre_low[],pre_high[],pre_volume[]; //---- count the amount of charts to be processed while(pos<=len) { curchar=StringGetChar(ChartList,pos); if(curchar>47 && curchar<58) { cur_period=cur_period+CharToStr(curchar); } else { if(curchar==',' || pos==len) { MarketInfo(cur_symbol,MODE_BID); if(GetLastError()==4106) { Alert("Unknown symbol ",cur_symbol,"!!!"); return(-1); } if(iClose(cur_symbol,StrToInteger(cur_period),0)<=0) { Alert("Unknown period ",cur_period,"!!!"); return(-1); } _Symbol[Charts]=cur_symbol; _Period[Charts]=StrToInteger(cur_period); cur_symbol=""; cur_period=""; Charts++; } else { cur_symbol=cur_symbol+CharToStr(curchar); } } pos++; } Print("< - - - Found ",Charts," correct charts. - - - >"); ArrayResize(_Symbol,Charts); ArrayResize(_Period,Charts); ArrayResize(HistoryHandle,Charts); ArrayResize(hwnd,Charts); ArrayResize(last_fpos,Charts); ArrayResize(pre_time,Charts); ArrayResize(now_time,Charts); ArrayResize(now_close,Charts); ArrayResize(now_open,Charts); ArrayResize(now_low,Charts); ArrayResize(now_high,Charts); ArrayResize(now_volume,Charts); ArrayResize(pre_close,Charts); ArrayResize(pre_open,Charts); ArrayResize(pre_low,Charts); ArrayResize(pre_high,Charts); ArrayResize(pre_volume,Charts); ArrayResize(_PeriodSec,Charts); ArrayResize(_Bars,Charts); for(int curChart=0; curChart<Charts; curChart++) { _PeriodSec[curChart]=_Period[curChart] *60; //---- open the file the history to be written in file_name=StringConcatenate("ALL",_Symbol[curChart], _Period[curChart],".hst"); HistoryHandle[curChart]=FileOpenHistory(file_name, FILE_BIN|FILE_WRITE); if(HistoryHandle[curChart]<0) { _GetLastError=GetLastError(); Alert("FileOpenHistory( \"",file_name,"\", FILE_BIN | FILE_WRITE )"," - Error #",_GetLastError); continue; } //---- Write the file heading FileWriteInteger(HistoryHandle[curChart],400,LONG_VALUE); FileWriteString(HistoryHandle[curChart], "Copyright © 2006, komposter",64); FileWriteString(HistoryHandle[curChart], StringConcatenate("ALL", _Symbol[curChart]),12); FileWriteInteger(HistoryHandle[curChart],_Period[curChart], LONG_VALUE); FileWriteInteger(HistoryHandle[curChart], MarketInfo(_Symbol[curChart], MODE_DIGITS),LONG_VALUE); FileWriteInteger(HistoryHandle[curChart],0, LONG_VALUE); //timesign FileWriteInteger(HistoryHandle[curChart],0, LONG_VALUE); //last_sync FileWriteArray(HistoryHandle[curChart],temp,0,13); //+-----------------------------------------------------------+ //| Process the history //+-----------------------------------------------------------+ _Bars[curChart]=iBars(_Symbol[curChart],_Period[curChart]); pre_time[curChart]=iTime(_Symbol[curChart], _Period[curChart],_Bars[curChart]-1); for(int i=_Bars[curChart]-1; i>=1; i--) { //---- Remember the bar parameters now_open[curChart]=iOpen(_Symbol[curChart], _Period[curChart],i); now_high[curChart]=iHigh(_Symbol[curChart], _Period[curChart],i); now_low[curChart]=iLow(_Symbol[curChart], _Period[curChart],i); now_close[curChart]=iClose(_Symbol[curChart], _Period[curChart],i); now_volume[curChart]=iVolume(_Symbol[curChart], _Period[curChart],i); now_time[curChart]=iTime(_Symbol[curChart], _Period[curChart],i) /_PeriodSec[curChart]; now_time[curChart]*=_PeriodSec[curChart]; //---- if there are skipped bars, while(now_time[curChart]>pre_time[curChart]+ _PeriodSec[curChart]) { pre_time[curChart]+=_PeriodSec[curChart]; pre_time[curChart] /= _PeriodSec[curChart]; pre_time[curChart] *= _PeriodSec[curChart]; //---- if this is not the weekend, if(SkipWeekEnd) { if(TimeDayOfWeek(pre_time[curChart])<=0 || TimeDayOfWeek(pre_time[curChart])>5) { continue; } if(TimeDayOfWeek(pre_time[curChart])==5) { if(TimeHour(pre_time[curChart])==23 || TimeHour(pre_time[curChart]+_PeriodSec[curChart])==23) { continue; } } } //---- write the skipped bar into the file FileWriteInteger(HistoryHandle[curChart],pre_time[curChart], LONG_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart],0, DOUBLE_VALUE); FileFlush(HistoryHandle[curChart]); cnt_add++; } //---- write the new bar into the file FileWriteInteger(HistoryHandle[curChart],now_time[curChart], LONG_VALUE); FileWriteDouble(HistoryHandle[curChart], now_open[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], now_low[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], now_high[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], now_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], now_volume[curChart],DOUBLE_VALUE); FileFlush(HistoryHandle[curChart]); cnt_copy++; //---- remember the time value and the close price //---- of the recorded bar pre_close[curChart]=now_close[curChart]; pre_time[curChart]=now_time[curChart]/ _PeriodSec[curChart]; pre_time[curChart]*=_PeriodSec[curChart]; } last_fpos[curChart]=FileTell(HistoryHandle[curChart]); //---- display statistics Print("< - - - ",_Symbol[curChart],_Period[curChart],": there were ", cnt_copy," bars, added ",cnt_add," bars - - - >"); Print("< - - - To view the results, open chart \"ALL", _Symbol[curChart],_Period[curChart],"\" - - - >"); } //+---------------------------------------------------------------+ //| Process the incoming ticks //+---------------------------------------------------------------+ while(!IsStopped()) { RefreshRates(); for(curChart=0; curChart<Charts; curChart++) { //---- put the "cursor" before the latest bar //---- (this must be done at all launches except for the first one) FileSeek(HistoryHandle[curChart],last_fpos[curChart], SEEK_SET); //---- Remember the bar parameters now_open[curChart]=iOpen(_Symbol[curChart], _Period[curChart],0); now_high[curChart]=iHigh(_Symbol[curChart], _Period[curChart],0); now_low[curChart]=iLow(_Symbol[curChart], _Period[curChart],0); now_close[curChart]=iClose(_Symbol[curChart], _Period[curChart],0); now_volume[curChart]=iVolume(_Symbol[curChart], _Period[curChart],0); now_time[curChart]=iTime(_Symbol[curChart], _Period[curChart],0) /_PeriodSec[curChart]; now_time[curChart]*=_PeriodSec[curChart]; //---- if a bar has been formed, if(now_time[curChart]>=pre_time[curChart]+ _PeriodSec[curChart]) { //---- write the formed bar FileWriteInteger(HistoryHandle[curChart],pre_time[curChart], LONG_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_open[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_low[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_high[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_volume[curChart],DOUBLE_VALUE); FileFlush(HistoryHandle[curChart]); //---- remember the position in the file before recording the 0th bar last_fpos[curChart]=FileTell(HistoryHandle[curChart]); } //---- if skipped bars appear, while(now_time[curChart]>pre_time[curChart]+_PeriodSec[curChart]) { pre_time[curChart] += _PeriodSec[curChart]; pre_time[curChart] /= _PeriodSec[curChart]; pre_time[curChart] *= _PeriodSec[curChart]; //---- if this is not the weekend, if(SkipWeekEnd) { if(TimeDayOfWeek(pre_time[curChart])<=0 || TimeDayOfWeek(pre_time[curChart])>5) { continue; } if(TimeDayOfWeek(pre_time[curChart])==5) { if(TimeHour(pre_time[curChart])==23 || TimeHour(pre_time[curChart]+_PeriodSec[curChart])==23) { continue; } } } //---- write the skipped bar into the file FileWriteInteger(HistoryHandle[curChart],pre_time[curChart], LONG_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], pre_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart],0, DOUBLE_VALUE); FileFlush(HistoryHandle[curChart]); //---- remember the position in the file before to record the 0th bar last_fpos[curChart]=FileTell(HistoryHandle[curChart]); } //---- write the current bar FileWriteInteger(HistoryHandle[curChart],now_time[curChart], LONG_VALUE); FileWriteDouble(HistoryHandle[curChart], now_open[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], now_low[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], now_high[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], now_close[curChart],DOUBLE_VALUE); FileWriteDouble(HistoryHandle[curChart], now_volume[curChart],DOUBLE_VALUE); FileFlush(HistoryHandle[curChart]); //---- remember the parameters of the written bar pre_open[curChart] = now_open[curChart]; pre_high[curChart] = now_high[curChart]; pre_low[curChart]=now_low[curChart]; pre_close[curChart]=now_close[curChart]; pre_volume[curChart]=now_volume[curChart]; pre_time[curChart]=now_time[curChart]/ _PeriodSec[curChart]; pre_time[curChart]*=_PeriodSec[curChart]; //---- find the window to "send" the new quotes to if(hwnd[curChart]==0) { hwnd[curChart]=WindowHandle(StringConcatenate("ALL", _Symbol[curChart]), _Period[curChart]); if(hwnd[curChart]!=0) { Print("< - - - Chart ","ALL"+_Symbol[curChart], _Period[curChart]," found! - - - >"); } } //---- and, if found, update it if(hwnd[curChart]!=0) { PostMessageA(hwnd[curChart],WM_COMMAND,33324,0); } } Sleep(RefreshLuft); } for(curChart=0; curChart<Charts; curChart++) { if(HistoryHandle[curChart]>=0) { //---- close the file FileClose(HistoryHandle[curChart]); HistoryHandle[curChart]=-1; } } return(0); }
Agora vamos inicializar o expert no gráfico de 5 minutos EURUSD com o parâmetro ChartList sendo igual a "EURUSD1,GBPUSD1,EURGBP1", e abrir todos os três gráficos no modo offline:
Tudo parece estar bem: Todos os três gráficos são atualizados simultaneamente e serão "reparados" caso surjam alguns buracos.
Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/1407
- 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