forked from zjwzjw20062007/MQL5Book
		
	
		
			
	
	
		
			234 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
		
		
			
		
	
	
			234 lines
		
	
	
	
		
			7.6 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//|                                        CalendarMonitorCached.mq5 |
							 | 
						||
| 
								 | 
							
								//|                              Copyright (c) 2022, MetaQuotes Ltd. |
							 | 
						||
| 
								 | 
							
								//|                                             https://www.mql5.com |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								#property copyright "Copyright (c) 2022, MetaQuotes Ltd."
							 | 
						||
| 
								 | 
							
								#property description "Output a table with selected calendar events."
							 | 
						||
| 
								 | 
							
								#property indicator_chart_window
							 | 
						||
| 
								 | 
							
								#property indicator_buffers 0
							 | 
						||
| 
								 | 
							
								#property indicator_plots   0
							 | 
						||
| 
								 | 
							
								#property tester_file "xyz.cal"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#define LOGGING
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\CalendarFilterCached.mqh"
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\CalendarCache.mqh"
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\Tableau.mqh"
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\AutoPtr.mqh"
							 | 
						||
| 
								 | 
							
								#include "..\..\Include\StringUtils.mqh"
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| I N P U T S                                                      |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								input group "General filters";
							 | 
						||
| 
								 | 
							
								input string Context; // Context (country - 2 chars, currency - 3 chars, empty - all)
							 | 
						||
| 
								 | 
							
								input ENUM_CALENDAR_SCOPE Scope = SCOPE_WEEK;
							 | 
						||
| 
								 | 
							
								input bool UseChartCurrencies = true;
							 | 
						||
| 
								 | 
							
								input string CalendarCacheFile = "xyz.cal";
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								input group "Optional filters";
							 | 
						||
| 
								 | 
							
								input ENUM_CALENDAR_EVENT_TYPE_EXT Type = TYPE_ANY;
							 | 
						||
| 
								 | 
							
								input ENUM_CALENDAR_EVENT_SECTOR_EXT Sector = SECTOR_ANY;
							 | 
						||
| 
								 | 
							
								input ENUM_CALENDAR_EVENT_IMPORTANCE_EXT Importance = IMPORTANCE_MODERATE; // Importance (at least)
							 | 
						||
| 
								 | 
							
								input string Text;
							 | 
						||
| 
								 | 
							
								input ENUM_CALENDAR_HAS_VALUE HasActual = HAS_ANY;
							 | 
						||
| 
								 | 
							
								input ENUM_CALENDAR_HAS_VALUE HasForecast = HAS_ANY;
							 | 
						||
| 
								 | 
							
								input ENUM_CALENDAR_HAS_VALUE HasPrevious = HAS_ANY;
							 | 
						||
| 
								 | 
							
								input ENUM_CALENDAR_HAS_VALUE HasRevised = HAS_ANY;
							 | 
						||
| 
								 | 
							
								input int Limit = 30;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								input group "Rendering settings";
							 | 
						||
| 
								 | 
							
								input ENUM_BASE_CORNER Corner = CORNER_RIGHT_LOWER;
							 | 
						||
| 
								 | 
							
								input int Margins = 8;
							 | 
						||
| 
								 | 
							
								input int FontSize = 8;
							 | 
						||
| 
								 | 
							
								input string FontName = "Consolas";
							 | 
						||
| 
								 | 
							
								input color BackgroundColor = clrSilver;
							 | 
						||
| 
								 | 
							
								input uchar BackgroundTransparency = 128;    // BackgroundTransparency (255 - opaque, 0 - glassy)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| G L O B A L S                                                    |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								AutoPtr<CalendarFilter> fptr;
							 | 
						||
| 
								 | 
							
								AutoPtr<Tableau> t;
							 | 
						||
| 
								 | 
							
								AutoPtr<CalendarCache> cache;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Custom indicator initialization function                         |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								int OnInit()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   cache = new CalendarCache(CalendarCacheFile, true);
							 | 
						||
| 
								 | 
							
								   if(cache[].isLoaded())
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      fptr = new CalendarFilterCached(cache[]);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   else
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(MQLInfoInteger(MQL_TESTER))
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         Print("Can't run in the tester without calendar cache file");
							 | 
						||
| 
								 | 
							
								         return INIT_FAILED;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else
							 | 
						||
| 
								 | 
							
								      if(StringLen(CalendarCacheFile))
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         Alert("Calendar cache not found, trying to create '" + CalendarCacheFile + "'");
							 | 
						||
| 
								 | 
							
								         cache = new CalendarCache();
							 | 
						||
| 
								 | 
							
								         if(cache[].save(CalendarCacheFile))
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            Alert("File saved. Re-run indicator in online chart or in the tester");
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         else
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            Alert("Error: ", _LastError);
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         ChartIndicatorDelete(0, 0, MQLInfoString(MQL_PROGRAM_NAME));
							 | 
						||
| 
								 | 
							
								         return INIT_PARAMETERS_INCORRECT;
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      Alert("Currently working in online mode (no cache)");
							 | 
						||
| 
								 | 
							
								      fptr = new CalendarFilter(Context);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   CalendarFilter *f = fptr[];
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   if(!f.isLoaded()) return INIT_FAILED;
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   if(UseChartCurrencies)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      const string base = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_BASE);
							 | 
						||
| 
								 | 
							
								      const string profit = SymbolInfoString(_Symbol, SYMBOL_CURRENCY_PROFIT);
							 | 
						||
| 
								 | 
							
								      f.let(base);
							 | 
						||
| 
								 | 
							
								      if(base != profit)
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         f.let(profit);
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   if(Type != TYPE_ANY)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      f.let((ENUM_CALENDAR_EVENT_TYPE)Type);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   if(Sector != SECTOR_ANY)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      f.let((ENUM_CALENDAR_EVENT_SECTOR)Sector);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   if(Importance != IMPORTANCE_ANY)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      f.let((ENUM_CALENDAR_EVENT_IMPORTANCE)(Importance - 1), GREATER);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   if(StringLen(Text))
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      f.let(Text);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   if(HasActual != HAS_ANY)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      f.let(LONG_MIN, CALENDAR_PROPERTY_RECORD_ACTUAL, HasActual == HAS_SET ? NOT_EQUAL : EQUAL);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   if(HasPrevious != HAS_ANY)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      f.let(LONG_MIN, CALENDAR_PROPERTY_RECORD_PREVIOUS, HasPrevious == HAS_SET ? NOT_EQUAL : EQUAL);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   if(HasRevised != HAS_ANY)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      f.let(LONG_MIN, CALENDAR_PROPERTY_RECORD_REVISED, HasRevised == HAS_SET ? NOT_EQUAL : EQUAL);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   if(HasForecast != HAS_ANY)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      f.let(LONG_MIN, CALENDAR_PROPERTY_RECORD_FORECAST, HasForecast == HAS_SET ? NOT_EQUAL : EQUAL);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   EventSetTimer(1);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   return INIT_SUCCEEDED;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Timer event handler (main processing of calendar goes here)      |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								void OnTimer()
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   CalendarFilter *f = fptr[];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   static const ENUM_CALENDAR_PROPERTY props[] =
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_RECORD_TIME,
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_COUNTRY_CURRENCY,
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_EVENT_NAME,
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_EVENT_IMPORTANCE,
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_RECORD_ACTUAL,
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_RECORD_FORECAST,
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_RECORD_PREVISED,
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_RECORD_IMPACT,
							 | 
						||
| 
								 | 
							
								      CALENDAR_PROPERTY_EVENT_SECTOR,
							 | 
						||
| 
								 | 
							
								   };
							 | 
						||
| 
								 | 
							
								   static const int p = ArraySize(props);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   MqlCalendarValue records[];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   f.let(TimeTradeServer() - Scope, TimeTradeServer() + Scope);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   const ulong trackID = f.getChangeID();
							 | 
						||
| 
								 | 
							
								   if(trackID) // already has a state, try to detect changes
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      if(f.update(records)) // find changes that match filters
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         // notify user about new changes
							 | 
						||
| 
								 | 
							
								         string result[];
							 | 
						||
| 
								 | 
							
								         f.format(records, props, result);
							 | 
						||
| 
								 | 
							
								         for(int i = 0; i < ArraySize(result) / p; ++i)
							 | 
						||
| 
								 | 
							
								         {
							 | 
						||
| 
								 | 
							
								            Alert(SubArrayCombine(result, " | ", i * p, p));
							 | 
						||
| 
								 | 
							
								         }
							 | 
						||
| 
								 | 
							
								         // fall through to the table redraw
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      else if(trackID == f.getChangeID())
							 | 
						||
| 
								 | 
							
								      {
							 | 
						||
| 
								 | 
							
								         return; // no changes in the calendar
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   // request complete set of events according to filters
							 | 
						||
| 
								 | 
							
								   f.select(records, true, Limit);
							 | 
						||
| 
								 | 
							
								   
							 | 
						||
| 
								 | 
							
								   // rebuild the table displayed on chart
							 | 
						||
| 
								 | 
							
								   string result[];
							 | 
						||
| 
								 | 
							
								   f.format(records, props, result, true, true);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   /*
							 | 
						||
| 
								 | 
							
								   // on-chart table copy in the log
							 | 
						||
| 
								 | 
							
								   for(int i = 0; i < ArraySize(result) / p; ++i)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      Print(SubArrayCombine(result, " | ", i * p, p));
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   */
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								   if(t[] == NULL || t[].getRows() != ArraySize(records) + 1)
							 | 
						||
| 
								 | 
							
								   {
							 | 
						||
| 
								 | 
							
								      t = new Tableau("CALT", ArraySize(records) + 1, p,
							 | 
						||
| 
								 | 
							
								         TBL_CELL_HEIGHT_AUTO, TBL_CELL_WIDTH_AUTO,
							 | 
						||
| 
								 | 
							
								         Corner, Margins, FontSize, FontName, FontName + " Bold",
							 | 
						||
| 
								 | 
							
								         TBL_FLAG_ROW_0_HEADER,
							 | 
						||
| 
								 | 
							
								         BackgroundColor, BackgroundTransparency);
							 | 
						||
| 
								 | 
							
								   }
							 | 
						||
| 
								 | 
							
								   const string hints[] = {};
							 | 
						||
| 
								 | 
							
								   t[].fill(result, hints);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								//| Custom indicator iteration function (dummy here)                 |
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 | 
						||
| 
								 | 
							
								int OnCalculate(const int rates_total,
							 | 
						||
| 
								 | 
							
								                const int prev_calculated,
							 | 
						||
| 
								 | 
							
								                const int begin,
							 | 
						||
| 
								 | 
							
								                const double &price[])
							 | 
						||
| 
								 | 
							
								{
							 | 
						||
| 
								 | 
							
								   return rates_total;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								//+------------------------------------------------------------------+
							 |