forked from zjwzjw20062007/MQL5Book
		
	
		
			
	
	
		
			120 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
		
		
			
		
	
	
			120 lines
		
	
	
	
		
			3.9 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//|                                          CalendarChangeSaver.mq5 |
							 | 
						||
| 
								 | 
							
								//|                                  Copyright 2022, MetaQuotes Ltd. |
							 | 
						||
| 
								 | 
							
								//|                                             https://www.mql5.com |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								#property copyright   "Copyright 2022, MetaQuotes Ltd."
							 | 
						||
| 
								 | 
							
								#property link        "https://www.mql5.com"
							 | 
						||
| 
								 | 
							
								#property description "Periodically request and save calendar change IDs and their timestamps."
							 | 
						||
| 
								 | 
							
								#property service
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define PACK_DATETIME_COUNTER(D,C) (D | (((ulong)(C)) << 48))
							 | 
						||
| 
								 | 
							
								#define DATETIME(A) ((datetime)((A) & 0x7FFFFFFFF))
							 | 
						||
| 
								 | 
							
								#define COUNTER(A)  ((ushort)((A) >> 48))
							 | 
						||
| 
								 | 
							
								#define BULK_LIMIT  100
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								input string Filename = "calendar.chn";
							 | 
						||
| 
								 | 
							
								input int PeriodMsc = 1000;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Generate user-friendly short description of the event            |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								string Description(const MqlCalendarValue &value)
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   MqlCalendarEvent event;
							 | 
						||
| 
								 | 
							
								   MqlCalendarCountry country;
							 | 
						||
| 
								 | 
							
								   CalendarEventById(value.event_id, event);
							 | 
						||
| 
								 | 
							
								   CalendarCountryById(event.country_id, country);
							 | 
						||
| 
								 | 
							
								   return StringFormat("%lld (%s/%s @ %s)",
							 | 
						||
| 
								 | 
							
								      value.id, country.code, event.name, TimeToString(value.time));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Service program start function                                   |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								void OnStart()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   bool online = true;
							 | 
						||
| 
								 | 
							
								   ulong change = 0, last = 0;
							 | 
						||
| 
								 | 
							
								   int count = 0;
							 | 
						||
| 
								 | 
							
								   int handle = FileOpen(Filename,
							 | 
						||
| 
								 | 
							
								      FILE_WRITE | FILE_READ | FILE_SHARE_WRITE | FILE_SHARE_READ | FILE_BIN);
							 | 
						||
| 
								 | 
							
								   if(handle == INVALID_HANDLE)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      PrintFormat("Can't open file '%s' for writing", Filename);
							 | 
						||
| 
								 | 
							
								      return;
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   const ulong p = FileSize(handle);
							 | 
						||
| 
								 | 
							
								   if(p > 0)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      PrintFormat("Resuming file %lld bytes", p);
							 | 
						||
| 
								 | 
							
								      FileSeek(handle, 0, SEEK_END);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   Print("Requesting start ID...");
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   while(!IsStopped())
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(!TerminalInfoInteger(TERMINAL_CONNECTED))
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         if(online)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            Print("Waiting for connection...");
							 | 
						||
| 
								 | 
							
								            online = false;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         Sleep(PeriodMsc);
							 | 
						||
| 
								 | 
							
								         continue;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else if(!online)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         Print("Connected");
							 | 
						||
| 
								 | 
							
								         online = true;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      MqlCalendarValue values[];
							 | 
						||
| 
								 | 
							
								      const int n = CalendarValueLast(change, values);
							 | 
						||
| 
								 | 
							
								      if(n > 0)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         // check for unreliable responce from terminal,
							 | 
						||
| 
								 | 
							
								         // when outdated irrelevant changes are returned,
							 | 
						||
| 
								 | 
							
								         // which usually happens just after terminal start-up
							 | 
						||
| 
								 | 
							
								         if(n >= BULK_LIMIT)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            Print("New change ID: ", change);
							 | 
						||
| 
								 | 
							
								            PrintFormat("Too many records (%d), malfunction assumed, skipping", n);
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         else
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            string records = "[" + Description(values[0]);
							 | 
						||
| 
								 | 
							
								            for(int i = 1; i < n; ++i)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               records += "," + Description(values[i]);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            records += "]";
							 | 
						||
| 
								 | 
							
								            Print("New change ID: ", change, " ",
							 | 
						||
| 
								 | 
							
								               TimeToString(TimeTradeServer(), TIME_DATE | TIME_SECONDS), "\n", records);
							 | 
						||
| 
								 | 
							
								            FileWriteLong(handle, PACK_DATETIME_COUNTER(TimeTradeServer(), n));
							 | 
						||
| 
								 | 
							
								            for(int i = 0; i < n; ++i)
							 | 
						||
| 
								 | 
							
								            {
							 | 
						||
| 
								 | 
							
								               FileWriteLong(handle, values[i].id);
							 | 
						||
| 
								 | 
							
								            }
							 | 
						||
| 
								 | 
							
								            FileFlush(handle);
							 | 
						||
| 
								 | 
							
								            ++count;
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else if(_LastError == 0)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         if(!last && change)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            Print("Start change ID obtained: ", change);
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      
							 | 
						||
| 
								 | 
							
								      last = change;
							 | 
						||
| 
								 | 
							
								      Sleep(PeriodMsc);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   PrintFormat("%d records added", count);
							 | 
						||
| 
								 | 
							
								   FileClose(handle);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 |