MQL5Book/Indicators/p7/CalendarMonitorCached.mq5
super.admin 1c8e83ce31 convert
2025-05-30 16:09:41 +02:00

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;
}
//+------------------------------------------------------------------+