geforkt von airat77786/MQL5Book
205 Zeilen
6,1 KiB
MQL5
205 Zeilen
6,1 KiB
MQL5
//+------------------------------------------------------------------+
| |||
//| CustomSymbolMonitor.mqh |
| |||
//| Copyright 2022, MetaQuotes Ltd. |
| |||
//| https://www.mql5.com |
| |||
//+------------------------------------------------------------------+
| |||
#include "EnumToArray.mqh"
| |||
#include "SymbolMonitor.mqh"
| |||
#include "AutoPtr.mqh"
| |||
#include "MqlError.mqh"
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Main class for reading and writing custom symbol properties |
| |||
//+------------------------------------------------------------------+
| |||
class CustomSymbolMonitor: public SymbolMonitor
| |||
{
| |||
protected:
| |||
AutoPtr<const SymbolMonitor> origin;
| |||
bool warningsOff;
| |||
int errorCount;
| |||
int mismatchCount;
| |||
int fixes;
| |||
| |||
template<typename E>
| |||
static bool detect(const int v)
| |||
{
| |||
ResetLastError();
| |||
const string s = EnumToString((E)v); // resulting string is not used
| |||
if(_LastError == 0) // only error code is important
| |||
{
| |||
return true;
| |||
}
| |||
return false;
| |||
}
| |||
| |||
template<typename E>
| |||
bool verify(const int i)
| |||
{
| |||
if(detect<E>(i))
| |||
{
| |||
if(get((E)i) != origin[].get((E)i))
| |||
{
| |||
if(!warningsOff)
| |||
{
| |||
Print("Fixing ", EnumToString((E)i), ": ", get((E)i), " <<< ", origin[].get((E)i));
| |||
}
| |||
set((E)i);
| |||
fixes++;
| |||
}
| |||
return true;
| |||
}
| |||
return false;
| |||
}
| |||
| |||
public:
| |||
CustomSymbolMonitor(): SymbolMonitor(), origin(NULL), warningsOff(false) { }
| |||
CustomSymbolMonitor(const string s, const SymbolMonitor *m = NULL): SymbolMonitor(s), origin(m), warningsOff(false) { }
| |||
CustomSymbolMonitor(const string s, const string other): SymbolMonitor(s), origin(new SymbolMonitor(other)), warningsOff(false) { }
| |||
| |||
void inherit(const SymbolMonitor &m)
| |||
{
| |||
origin = &m;
| |||
}
| |||
| |||
bool setAll(const bool reverseOrder = true, const int limit = UCHAR_MAX)
| |||
{
| |||
int properties[];
| |||
ArrayResize(properties, limit);
| |||
for(int i = 0; i < limit; ++i)
| |||
{
| |||
properties[i] = reverseOrder ? limit - i - 1 : i; // NB: number of errors differs in direct and reverse order
| |||
}
| |||
warningsOff = true;
| |||
errorCount = 0;
| |||
mismatchCount = 0;
| |||
const bool success = set(properties);
| |||
warningsOff = false;
| |||
Print("Errors: ", errorCount);
| |||
Print("Mismatches: ", mismatchCount);
| |||
return success;
| |||
}
| |||
| |||
int verifyAll(const int limit = UCHAR_MAX)
| |||
{
| |||
int properties[];
| |||
ArrayResize(properties, limit);
| |||
for(int i = 0; i < limit; ++i)
| |||
{
| |||
properties[i] = i;
| |||
}
| |||
return verify(properties);
| |||
}
| |||
| |||
int verify(const int &properties[])
| |||
{
| |||
if(origin[] == NULL) return 0;
| |||
fixes = 0;
| |||
for(int i = 0; i < ArraySize(properties); ++i)
| |||
{
| |||
if(verify<ENUM_SYMBOL_INFO_INTEGER>(properties[i])
| |||
|| verify<ENUM_SYMBOL_INFO_DOUBLE>(properties[i])
| |||
|| verify<ENUM_SYMBOL_INFO_STRING>(properties[i]))
| |||
{
| |||
// ok
| |||
}
| |||
else
| |||
{
| |||
break; // unknown property: should not happen
| |||
}
| |||
}
| |||
return fixes;
| |||
}
| |||
| |||
bool set(const int &properties[])
| |||
{
| |||
bool success = true;
| |||
for(int i = 0; i < ArraySize(properties); ++i)
| |||
{
| |||
if(detect<ENUM_SYMBOL_INFO_INTEGER>(properties[i]))
| |||
{
| |||
success = set((ENUM_SYMBOL_INFO_INTEGER)properties[i]) && success;
| |||
}
| |||
else if(detect<ENUM_SYMBOL_INFO_DOUBLE>(properties[i]))
| |||
{
| |||
success = set((ENUM_SYMBOL_INFO_DOUBLE)properties[i]) && success;
| |||
}
| |||
else if(detect<ENUM_SYMBOL_INFO_STRING>(properties[i]))
| |||
{
| |||
success = set((ENUM_SYMBOL_INFO_STRING)properties[i]) && success;
| |||
}
| |||
else if(!warningsOff)
| |||
{
| |||
Print("Unresolved int value as enum: ", i, " for ", name);
| |||
}
| |||
}
| |||
return success;
| |||
}
| |||
| |||
template<typename E>
| |||
bool set(const E e)
| |||
{
| |||
if(origin[])
| |||
{
| |||
ResetLastError();
| |||
const bool result = set(e, origin[].get(e));
| |||
PrintFormat("%s %s %s -> %s (%d)", (result ? "true " : "false"), EnumToString(e), (string)origin[].get(e), E2S(_LastError), _LastError);
| |||
if(result)
| |||
{
| |||
if(this.get(e) != origin[].get(e))
| |||
{
| |||
mismatchCount++;
| |||
Print("!!!Mismatch!!! ", this.get(e), " <-> ", origin[].get(e));
| |||
}
| |||
}
| |||
else
| |||
{
| |||
errorCount++;
| |||
}
| |||
return result;
| |||
}
| |||
return false;
| |||
}
| |||
| |||
bool set(const ENUM_SYMBOL_INFO_INTEGER property, const long value) const
| |||
{
| |||
return CustomSymbolSetInteger(name, property, value);
| |||
}
| |||
| |||
bool set(const ENUM_SYMBOL_INFO_DOUBLE property, const double value) const
| |||
{
| |||
return CustomSymbolSetDouble(name, property, value);
| |||
}
| |||
| |||
bool set(const ENUM_SYMBOL_INFO_STRING property, const string value) const
| |||
{
| |||
return CustomSymbolSetString(name, property, value);
| |||
}
| |||
};
| |||
| |||
//+------------------------------------------------------------------+
| |||
//| Example |
| |||
//+------------------------------------------------------------------+
| |||
/*
| |||
#include "CustomSymbolMonitor.mqh"
| |||
| |||
void OnStart()
| |||
{
| |||
const string custom = "ABCXYZ";
| |||
if(CustomSymbolCreate(custom, "", _Symbol))
| |||
{
| |||
CustomSymbolMonitor cs(custom, _Symbol);
| |||
int p[] = {SYMBOL_CURRENCY_BASE, SYMBOL_CURRENCY_PROFIT};
| |||
Print("Try 1 (may fail if _Symbol has SYMBOL_CALC_MODE_FOREX)");
| |||
cs.verify(p);
| |||
Print("Try 2 (will succeed)");
| |||
cs.set(SYMBOL_TRADE_CALC_MODE, SYMBOL_CALC_MODE_CFD);
| |||
cs.set(p);
| |||
cs.verify(p);
| |||
}
| |||
else
| |||
{
| |||
PrintFormat("Can't create symbol '%s': %s", custom, E2S(_LastError));
| |||
}
| |||
}
| |||
*/
| |||
//+------------------------------------------------------------------+
|