Adwizard/Virtual/VirtualAdvisor.mqh

601 lines
48 KiB
MQL5
Raw Permalink Normal View History

2025-04-11 13:28:40 +03:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| VirtualAdvisor.mqh |
//| Copyright 2019-2025, Yuriy Bykov |
//| https://www.mql5.com/ru/users/antekov |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019-2025, Yuriy Bykov"
#property link "https://www.mql5.com/ru/users/antekov"
#property version "1.11"
class CVirtualStrategyGroup;
#include "../Base/Advisor.mqh"
#include "../Utils/NewBarEvent.mqh"
#include "../Utils/SymbolsMonitor.mqh"
#include "VirtualRiskManager.mqh"
#include "VirtualInterface.mqh"
#include "VirtualReceiver.mqh"
#include "VirtualStrategyGroup.mqh"
#include "TesterHandler.mqh"
//+------------------------------------------------------------------+
//| ;0AA M:A?5@B0, @01>B0NI53> A 28@BC0;L=K<8 ?>78F8O<8 (>@45@0<8) |
//+------------------------------------------------------------------+
class CVirtualAdvisor : public CAdvisor {
protected:
CSymbolsMonitor *m_symbols; // 1J5:B <>=8B>@0 A8<2>;>2
CVirtualReceiver *m_receiver; // 1J5:B ?>;CG0B5;O, 2K2>4OI89 ?>78F88 =0 @K=>:
CVirtualInterface *m_interface; // 1J5:B 8=B5@D59A0 4;O ?>:070 A>AB>O=8O ?>;L7>20B5;N
CVirtualRiskManager *m_riskManager; // 1J5:B @8A:-<5=5465@0
string m_fileName; // 0720=85 D09;0 A 107>9 40==KE M:A?5@B0
datetime m_lastSaveTime; // @5<O ?>A;54=53> A>E@0=5=8O
bool m_useOnlyNewBar; // 1@010BK20BL B>;L:> B8:8 =>2>3> 10@0
datetime m_fromDate; // 0B0 =0G0;0 @01>BK
string m_paramsNorm; // 0@0<5B@K 3@C??K AB@0B5389 ?>A;5 =>@<8@>2:8
virtual void Add(CVirtualStrategyGroup *p_group); // 5B>4 4>102;5=8O 3@C??K AB@0B5389
static int s_groupId; // ID 703@C65==>9 87 107K 40==KE 3@C??K AB@0B5389
CVirtualAdvisor(string p_param); // >=AB@C:B>@
public:
STATIC_CONSTRUCTOR(CVirtualAdvisor);
~CVirtualAdvisor(); // 5AB@C:B>@
virtual string operator~() override; // @5>1@07>20=85 >1J5:B0 2 AB@>:C
virtual void Tick() override; // 1@01>BG8: A>1KB8O OnTick
virtual double Tester() override; // 1@01>BG8: A>1KB8O OnTester
// 1@01>BG8: A>1KB8O OnChartEvent (?>:0 =5 8A?>;L7C5BAO)
virtual void ChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam);
virtual bool Save(); // !>E@0=5=85 A>AB>O=8O
virtual bool Load(); // 03@C7:0 A>AB>O=8O
// 0<5=0 =0720=89 A8<2>;>2
bool SymbolsReplace(const string p_symbolsReplace);
// @>25@:0 =0;8G8O =>2>9 3@C??K AB@0B5389 2 1075 40==KE M:A?5@B0
bool CheckUpdate();
// -:A?>@B B5:CI59 3@C??K AB@0B5389 2 7040==CN 107C 40==KE M:A?5@B0
void Export(string p_groupName, string p_advFileName);
// 1@01>BG8: A>1KB8O OnTesterInit
static int TesterInit(ulong p_idTask = 0, string p_fileName = NULL);
static void TesterPass(); // 1@01>BG8: A>1KB8O OnTesterDeinit
static void TesterDeinit(); // 1@01>BG8: A>1KB8O OnTesterDeinit
// <O D09;0 A 107>9 40==KE M:A?5@B0
static string FileName(string p_name, ulong p_magic = 1);
// >;CG5=85 AB@>:8 8=8F80;870F88 3@C??K AB@0B5389
// 87 107K 40==KE M:A?5@B0 A 7040==K< 845=B8D8:0B>@><
static string Import(string p_fileName, int p_groupId = 0);
};
int CVirtualAdvisor::s_groupId = 0;
REGISTER_FACTORABLE_CLASS(CVirtualAdvisor);
//+------------------------------------------------------------------+
//| 5B>4 4>102;5=8O 3@C??K AB@0B5389 |
//+------------------------------------------------------------------+
void CVirtualAdvisor::Add(CVirtualStrategyGroup *p_group) {
// A;8 2 MB>9 3@C??5 A>45@60BAO 4@C385 3@C??K, B> 4>102;O5< :064CN 87 =8E
FOREACH(p_group.m_groups) {
CVirtualAdvisor::Add(p_group.m_groups[i]);
delete p_group.m_groups[i];
}
// A;8 2 MB>9 3@C??5 A>45@60BAO AB@0B5388, B> 4>102;O5< :064CN 87 =8E
FOREACH(p_group.m_strategies) CAdvisor::Add(p_group.m_strategies[i]);
}
//+------------------------------------------------------------------+
//| >=AB@C:B>@ |
//+------------------------------------------------------------------+
CVirtualAdvisor::CVirtualAdvisor(string p_params) {
// 0?><8=05< AB@>:C 8=8F80;870F88
m_params = p_params;
// '8B05< AB@>:C 8=8F80;870F88 >1J5:B0 3@C??K AB@0B5389
string groupParams = ReadObject(p_params);
// '8B05< AB@>:C 8=8F80;870F88 >1J5:B0 @8A:-<5=5465@0
string riskManagerParams = ReadObject(p_params);
// '8B05< <038G5A:89 =><5@
ulong p_magic = ReadLong(p_params);
// '8B05< =0720=85 M:A?5@B0
string p_name = ReadString(p_params);
// '8B05< ?@87=0: @01>BK =0 B>;L:> =0 >B:@KB88 10@0
m_useOnlyNewBar = (bool) ReadLong(p_params);
// A;8 =5B >H81>: GB5=8O, B>
if(IsValid()) {
// !>740Q< 3@C??C AB@0B5389
CREATE(CVirtualStrategyGroup, p_group, groupParams);
// =8F80;878@C5< <>=8B>@ A8<2>;>2 AB0B8G5A:8< <>=8B>@>< A8<2>;>2
m_symbols = CSymbolsMonitor::Instance();
// =8F80;878@C5< ?>;CG0B5;O AB0B8G5A:8< ?>;CG0B5;5<
m_receiver = CVirtualReceiver::Instance(p_magic);
// =8F80;878@C5< 8=B5@D59A AB0B8G5A:8< 8=B5@D59A><
m_interface = CVirtualInterface::Instance(p_magic);
// $>@<8@C5< 87 8<5=8 M:A?5@B0 8 ?0@0<5B@>2 8<O D09;0 107K 40==KE M:A?5@B0 4;O A>E@0=5=8O A>AB>O=8O
m_fileName = FileName(p_name, p_magic);
// 0?><8=05< 2@5<O =0G0;0 @01>BK (B5AB8@>20=8O)
m_fromDate = TimeCurrent();
// !1@0AK205< 2@5<O ?>A;54=53> A>E@0=5=8O
m_lastSaveTime = 0;
// >102;O5< : M:A?5@BC A>45@68<>5 3@C??K
Add(p_group);
// #40;O5< >1J5:B 3@C??K
delete p_group;
// !>740Q< >1J5:B @8A:-<5=5465@0
m_riskManager = NEW(riskManagerParams);
}
}
//+------------------------------------------------------------------+
//| 5AB@C:B>@ |
//+------------------------------------------------------------------+
void CVirtualAdvisor::~CVirtualAdvisor() {
if(!!m_symbols) delete m_symbols; // #40;O5< <>=8B>@ A8<2>;>2
if(!!m_receiver) delete m_receiver; // #40;O5< ?>;CG0B5;L
if(!!m_interface) delete m_interface; // #40;O5< 8=B5@D59A
if(!!m_riskManager) delete m_riskManager; // #40;O5< @8A:-<5=5465@
DestroyNewBar(); // #40;O5< >1J5:BK >BA;56820=8O =>2>3> 10@0
}
//+------------------------------------------------------------------+
//| @5>1@07>20=85 >1J5:B0 2 AB@>:C |
//+------------------------------------------------------------------+
string CVirtualAdvisor::operator~() {
return StringFormat("%s(%s)", typename(this), m_params);
}
//+------------------------------------------------------------------+
//| 1@01>BG8: A>1KB8O OnTick |
//+------------------------------------------------------------------+
void CVirtualAdvisor::Tick(void) {
// ?@545;O5< =>2K9 10@ ?> 2A5< =C6=K< A8<2>;0< 8 B09<D@59<0<
bool isNewBar = UpdateNewBar();
// A;8 =8345 =>2>3> 10@0 =5B, 0 <K @01>B05< B>;L:> ?> =>2K< 10@0<, B> 2KE>48<
if(!isNewBar && m_useOnlyNewBar) {
return;
}
// >=8B>@ A8<2>;>2 >1=>2;O5B :>B8@>2:8
m_symbols.Tick();
// >;CG0B5;L >1@010BK205B 28@BC0;L=K5 ?>78F88
m_receiver.Tick();
// 0?CA: >1@01>B:8 2 AB@0B538OE
CAdvisor::Tick();
// 8A:-<5=5465@ >1@010BK205B 28@BC0;L=K5 ?>78F88
m_riskManager.Tick();
// >@@5:B8@>2:0 @K=>G=KE >1J5<>2
m_receiver.Correct();
// !>E@0=5=85 A>AB>O=8O
Save();
// B@8A>2:0 8=B5@D59A0
m_interface.Redraw();
}
//+------------------------------------------------------------------+
//| 1@01>BG8: A>1KB8O OnTester |
//+------------------------------------------------------------------+
double CVirtualAdvisor::Tester() {
// 0:A8<0;L=0O 01A>;NB=0O ?@>A04:0
double balanceDrawdown = TesterStatistics(STAT_EQUITY_DD);
// @81K;L
double profit = TesterStatistics(STAT_PROFIT);
// $8:A8@>20==K9 10;0=A 4;O B>@3>2;8 87 =0AB@>5:
double fixedBalance = CMoney::FixedBalance();
// >MDD8F85=B 2>7<>6=>3> C25;8G5=8O @07<5@>2 ?>78F89 4;O ?@>A04:8 10% >B fixedBalance_
double coeff = fixedBalance * 0.1 / MathMax(1, balanceDrawdown);
// @5AG8BK205< ?@81K;L 2 3>4>2CN
long totalSeconds = TimeCurrent() - m_fromDate;
double totalYears = totalSeconds / (365.0 * 24 * 3600);
double fittedProfit = profit * coeff / totalYears;
// A;8 >= =5 C:070=, B> 15@Q< =0G0;L=K9 10;0=A (E>BO MB> 1C45B 4020BL 8A:06Q==K9 @57C;LB0B)
if(fixedBalance < 1) {
fixedBalance = TesterStatistics(STAT_INITIAL_DEPOSIT);
balanceDrawdown = TesterStatistics(STAT_EQUITY_DDREL_PERCENT);
coeff = 0.1 / MathMax(1, balanceDrawdown);
fittedProfit = fixedBalance * MathPow(1 + profit * coeff / fixedBalance, 1 / totalYears);
}
// >AA>740Q< 3@C??C 8A?>;L7>20==KE AB@0B5389 4;O ?>A;54CNI59 =>@<8@>2:8
CVirtualStrategyGroup* group = NEW(ReadObject(m_params));
if(!!group) {
// !B@>:0 8=8F80;870F88 =>@<8@>20==>9 3@C??K
m_paramsNorm = group.ToStringNorm(coeff);
FOREACH(m_strategies) ((CVirtualStrategy*)m_strategies[i]).Scale(coeff);
// K?>;=O5< D>@<8@>20=85 D@59<0 40==KE =0 035=B5 B5AB8@>20=8O
CTesterHandler::Tester(fittedProfit, // >@<8@>20==0O ?@81K;L
m_paramsNorm // !B@>:0 8=8F80;870F88 =>@<8@>20==>9 3@C??K
);
PrintFormat(__FUNCTION__" | Scale = %.2f\nParams:\n%s", coeff, m_paramsNorm);
PrintFormat(__FUNCTION__" | Scale = %.2f", coeff);
delete group;
}
PrintFormat(__FUNCTION__" |\n%s = %.2f\n%s = %.2f\n%s = %.2f\n%s = %.2f\n%s = %.2f\n",
EnumToString(STAT_BALANCE_DD), TesterStatistics(STAT_BALANCE_DD),
EnumToString(STAT_BALANCE_DD_RELATIVE), TesterStatistics(STAT_BALANCE_DD_RELATIVE),
EnumToString(STAT_EQUITY_DD), TesterStatistics(STAT_EQUITY_DD),
EnumToString(STAT_EQUITY_DD_RELATIVE), TesterStatistics(STAT_EQUITY_DD_RELATIVE),
EnumToString(STAT_EQUITY_DDREL_PERCENT), TesterStatistics(STAT_EQUITY_DDREL_PERCENT)
);
return fittedProfit;
}
//+------------------------------------------------------------------+
//| -:A?>@B B5:CI59 3@C??K AB@0B5389 2 7040==CN 107C 40==KE M:A?5@B0 |
//+------------------------------------------------------------------+
void CVirtualAdvisor::Export(string p_groupName, string p_advFileName) {
CTesterHandler::Export(m_strategies, p_groupName, p_advFileName);
}
//+------------------------------------------------------------------+
//| 1@01>BG8: A>1KB89 ChartEvent |
//+------------------------------------------------------------------+
void CVirtualAdvisor::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) {
m_interface.ChartEvent(id, lparam, dparam, sparam);
}
//+------------------------------------------------------------------+
//| =8F80;870F8O ?5@54 =0G0;>< >?B8<870F88 |
//+------------------------------------------------------------------+
int CVirtualAdvisor::TesterInit(ulong p_idTask, string p_fileName) {
return CTesterHandler::TesterInit(p_idTask, p_fileName);
}
//+------------------------------------------------------------------+
//| 59AB28O ?>A;5 7025@H5=8O >G5@54=>3> ?@>E>40 ?@8 >?B8<870F88 |
//+------------------------------------------------------------------+
void CVirtualAdvisor::TesterPass() {
CTesterHandler::TesterPass();
}
//+------------------------------------------------------------------+
//| 59AB28O ?>A;5 7025@H5=8O >?B8<870F88 |
//+------------------------------------------------------------------+
void CVirtualAdvisor::TesterDeinit() {
CTesterHandler::TesterDeinit();
}
//+------------------------------------------------------------------+
//| !>E@0=5=85 A>AB>O=8O |
//+------------------------------------------------------------------+
bool CVirtualAdvisor::Save() {
// !>E@0=O5< A>AB>O=85, 5A;8:
if(true
// ?>O28;8AL 1>;55 ?>74=85 87<5=5=8O
&& m_lastSaveTime < CVirtualReceiver::s_lastChangeTime
// 8 A59G0A =5 >?B8<870F8O
&& !MQLInfoInteger(MQL_OPTIMIZATION)
// 8 A59G0A =5 B5AB8@>20=85 ;81> A59G0A 287C0;L=>5 B5AB8@>20=85
&& (!MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_VISUAL_MODE))
) {
// A;8 ?>4:;NG5=85 : 1075 40==KE M:A?5@B0 CAB0=>2;5=>
if(CStorage::Connect(m_fileName)) {
// !>E@0=O5< 2@5<O ?>A;54=8E 87<5=5=89
CStorage::Set("CVirtualReceiver::s_lastChangeTime", CVirtualReceiver::s_lastChangeTime);
CStorage::Set("CVirtualAdvisor::s_groupId", CVirtualAdvisor::s_groupId);
// !>E@0=O5< 2A5 AB@0B5388
FOREACH(m_strategies) ((CVirtualStrategy*) m_strategies[i]).Save();
// !>E@0=O5< @8A:-<5=5465@
m_riskManager.Save();
// 1=>2;O5< 2@5<O ?>A;54=53> A>E@0=5=8O
m_lastSaveTime = CVirtualReceiver::s_lastChangeTime;
PrintFormat(__FUNCTION__" | OK at %s to %s",
TimeToString(m_lastSaveTime, TIME_DATE | TIME_MINUTES | TIME_SECONDS),
m_fileName);
// 0:@K205< A>548=5=85
CStorage::Close();
// >72@0I05< @57C;LB0B
return CStorage::Res();
} else {
PrintFormat(__FUNCTION__" | ERROR: Can't open database [%s], LastError=%d",
m_fileName, GetLastError());
return false;
}
}
return true;
}
//+------------------------------------------------------------------+
//| 03@C7:0 A>AB>O=8O |
//+------------------------------------------------------------------+
bool CVirtualAdvisor::Load() {
bool res = true;
ulong groupId = 0;
// 03@C605< A>AB>O=85, 5A;8:
if(true
// D09; ACI5AB2C5B
&& FileIsExist(m_fileName, FILE_COMMON)
// 8 A59G0A =5 >?B8<870F8O
&& !MQLInfoInteger(MQL_OPTIMIZATION)
// 8 A59G0A =5 B5AB8@>20=85 ;81> A59G0A 287C0;L=>5 B5AB8@>20=85
&& (!MQLInfoInteger(MQL_TESTER) || MQLInfoInteger(MQL_VISUAL_MODE))
) {
// A;8 ?>4:;NG5=85 : 1075 40==KE M:A?5@B0 CAB0=>2;5=>
if(CStorage::Connect(m_fileName)) {
// A;8 2@5<O ?>A;54=8E 87<5=5=89 703@C65=> 8 <5=LH5 B5:CI53> 2@5<5=8
if(CStorage::Get("CVirtualReceiver::s_lastChangeTime", m_lastSaveTime)
&& m_lastSaveTime <= TimeCurrent()) {
PrintFormat(__FUNCTION__" | LAST SAVE at %s",
TimeToString(m_lastSaveTime, TIME_DATE | TIME_MINUTES | TIME_SECONDS));
// A;8 845=B8D8:0B>@ A>E@0=Q==>9 3@C??K AB@0B5389 703@C65=
if(CStorage::Get("CVirtualAdvisor::s_groupId", groupId)) {
// 03@C605< 2A5 AB@0B5388, 83=>@8@CO 2>7<>6=K5 >H81:8
FOREACH(m_strategies) {
res &= ((CVirtualStrategy*) m_strategies[i]).Load();
}
if(groupId != s_groupId) {
// 59AB28O ?@8 70?CA:5 M:A?5@B0 A =>2>9 3@C??>9 AB@0B5389.
PrintFormat(__FUNCTION__" | UPDATE Group ID: %I64u -> %I64u", groupId, s_groupId);
// !1@0AK205< 2>7<>6=K9 ?@87=0: >H81:8 ?@8 703@C7:5 AB@0B5389
res = true;
string symbols[]; // 0AA82 4;O =0720=89 A8<2>;>0
// >;CG05< A?8A>: 2A5E 8A?>;L7C5<KE ?@54K4CI59 3@C??>9 A8<2>;>2
CStorage::GetSymbols(symbols);
// ;O 2A5E A8<2>;>2 A>740Q< A8<2>;L=K9 ?>;CG0B5;L.
// -B> =C6=> 4;O :>@@5:B=>3> 70:@KB8O 28@BC0;L=KE ?>78F89
// AB0@>9 3@C??K AB@0B5389 A@07C ?>A;5 703@C7:8 =>2>9
FOREACH(symbols) m_receiver[symbols[i]];
}
if(res) {
// 03@C605< @8A:-<5=5465@
res &= m_riskManager.Load();
if(!res) {
PrintFormat(__FUNCTION__" | ERROR loading risk manager from DB [%s]", m_fileName);
}
} else {
PrintFormat(__FUNCTION__" | ERROR loading strategies from DB [%s]", m_fileName);
}
}
} else {
// A;8 2@5<O ?>A;54=8E 87<5=5=89 =5 =0945=> 8;8 =0E>48BAO 2 1C4CI5<,
// B> =0G8=05< @01>BC A G8AB>3> ;8AB0
PrintFormat(__FUNCTION__" | NO LAST SAVE [%s] - Clear Storage",
TimeToString(m_lastSaveTime, TIME_DATE | TIME_MINUTES | TIME_SECONDS));
CStorage::Clear();
m_lastSaveTime = 0;
}
// 0:@K205< A>548=5=85
CStorage::Close();
}
}
return res;
}
//+------------------------------------------------------------------+
//| 0<5=0 =0720=89 A8<2>;>2 |
//+------------------------------------------------------------------+
bool CVirtualAdvisor::SymbolsReplace(string p_symbolsReplace) {
// 7102;O5<AO >B ?@>15;>2 2 AB@>:5 70<5=
StringReplace(p_symbolsReplace, " ", "");
// A;8 AB@>:0 70<5= ?CAB0O, B> =8G53> =5 45;05<
if(p_symbolsReplace == "") {
return true;
}
// 5@5<5==0O 4;O @57C;LB0B0
bool res = true;
string symbolKeyValuePairs[]; // 0AA82 4;O >B45;L=KE 70<5=
string symbolPair[]; // 0AA82 4;O 42CE 8<Q= 2 >4=>9 70<5=5
// 5;8< AB@>:C 70<5= =0 G0AB8, ?@54AB02;ONI85 >4=C >B45;L=CN 70<5=C
StringSplit(p_symbolsReplace, ';', symbolKeyValuePairs);
// !;>20@L 4;O A>>B25BAB28O F5;52>3> A8<2>;0 8AE>4=><C A8<2>;C
CHashMap<string, string> symbolsMap;
// ;O 2A5E >B45;L=KE 70<5=
FOREACH(symbolKeyValuePairs) {
// >;CG05< 8AE>4=K9 8 F5;52>9 A8<2>;K :0: 420 M;5<5=B0 <0AA820
StringSplit(symbolKeyValuePairs[i], '=', symbolPair);
// @>25@O5< =0;8G85 F5;52>3> A8<2>;0 2 A?8A:5 4>ABC?=KE A8<2>;>2 (=5 :0AB><=KE)
bool custom = false;
res &= SymbolExist(symbolPair[1], custom);
// A;8 F5;52>9 A8<2>; =5 =0945=, B> A>>1I05< >1 >H81:5 8 2KE>48<
if(!res) {
PrintFormat(__FUNCTION__" | ERROR: Target symbol %s for mapping %s not found", symbolPair[1], symbolKeyValuePairs[i]);
return res;
}
// >102;O5< 2 A;>20@L =>2K9 M;5<5=B: :;NG - 8AE>4=K9 A8<2>;, 7=0G5=85 - F5;52>9 A8<2>;
res &= symbolsMap.Add(symbolPair[0], symbolPair[1]);
// A;8 F5;52>9 A8<2>; =5 C40;>AL 4>1028BL 2 A;>20@L, B> A>>1I05< >1 >H81:5 8 2KE>48<
if(!res) {
PrintFormat(__FUNCTION__" | ERROR: Can't add symbol map pair %s to HashMap. Check your parameter:\n%s",
symbolKeyValuePairs[i], p_symbolsReplace);
return res;
}
}
// A;8 >H81>: =5 2>7=8:;>, B> 4;O 2A5E AB@0B5389 2K7K205< A>>B25BAB2CNI89 <5B>4 70<5=K
FOREACH(m_strategies) res &= ((CVirtualStrategy*) m_strategies[i]).SymbolsReplace(symbolsMap);
return res;
}
//+------------------------------------------------------------------+
//| @>25@:0 =0;8G8O =>2>9 3@C??K AB@0B5389 2 1075 40==KE M:A?5@B0 |
//+------------------------------------------------------------------+
bool CVirtualAdvisor::CheckUpdate() {
// 0?@>A =0 ?>;CG5=85 AB@0B5389 7040==>9 3@C??K ;81> ?>A;54=59 3@C??K
string query = StringFormat("SELECT MAX(id_group) FROM strategy_groups"
" WHERE to_date <= '%s'",
TimeToString(TimeCurrent(), TIME_DATE));
// B:@K205< 107C 40==KE M:A?5@B0
if(DB::Connect(m_fileName, DB_TYPE_ADV)) {
// K?>;=O5< 70?@>A
int request = DatabasePrepare(DB::Id(), query);
// A;8 =5B >H81:8
if(request != INVALID_HANDLE) {
// !B@C:BC@0 40==KE 4;O GB5=8O >4=>9 AB@>:8 @57C;LB0B0 70?@>A0
struct Row {
int groupId;
} row;
// '8B05< 40==K5 87 ?5@2>9 AB@>:8 @57C;LB0B0
while(DatabaseReadBind(request, row)) {
// 0?><8=05< 845=B8D8:0B>@ 3@C??K AB@0B5389
// 2 AB0B8G5A:>< A2>9AB25 :;0AA0 M:A?5@B0
return s_groupId < row.groupId;
}
} else {
// !>>1I05< >1 >H81:5 ?@8 =5>1E>48<>AB8
PrintFormat(__FUNCTION__" | ERROR: request \n%s\nfailed with code %d", query, GetLastError());
}
// 0:@K205< 107C 40==KE M:A?5@B0
DB::Close();
}
return false;
}
//+------------------------------------------------------------------+
//| >;CG5=85 AB@>:8 8=8F80;870F88 3@C??K AB@0B5389 |
//| 87 107K 40==KE M:A?5@B0 A 7040==K< 845=B8D8:0B>@>< |
//+------------------------------------------------------------------+
string CVirtualAdvisor::Import(string p_fileName, int p_groupId = 0) {
string params[]; // 0AA82 4;O AB@>: 8=8F80;870F88 AB@0B5389
// 0?@>A =0 ?>;CG5=85 AB@0B5389 7040==>9 3@C??K ;81> ?>A;54=59 3@C??K
string query = StringFormat("SELECT id_group, params "
" FROM strategies"
" WHERE id_group = %s;",
(p_groupId > 0 ? (string) p_groupId
: "(SELECT MAX(id_group) FROM strategy_groups WHERE to_date <= '"
+ TimeToString(TimeCurrent(), TIME_DATE) +
"')"));
// B:@K205< 107C 40==KE M:A?5@B0
if(DB::Connect(p_fileName, DB_TYPE_ADV)) {
// K?>;=O5< 70?@>A
int request = DatabasePrepare(DB::Id(), query);
// A;8 =5B >H81:8
if(request != INVALID_HANDLE) {
// !B@C:BC@0 40==KE 4;O GB5=8O >4=>9 AB@>:8 @57C;LB0B0 70?@>A0
struct Row {
int groupId;
string params;
} row;
// '8B05< 40==K5 87 ?5@2>9 AB@>:8 @57C;LB0B0
while(DatabaseReadBind(request, row)) {
// 0?><8=05< 845=B8D8:0B>@ 3@C??K AB@0B5389
// 2 AB0B8G5A:>< A2>9AB25 :;0AA0 M:A?5@B0
s_groupId = row.groupId;
// >102;O5< >G5@54=CN AB@>:C 8=8F80;870F88 AB@0B5388 2 <0AA82
APPEND(params, row.params);
}
} else {
// !>>1I05< >1 >H81:5 ?@8 =5>1E>48<>AB8
PrintFormat(__FUNCTION__" | ERROR: request \n%s\nfailed with code %d", query, GetLastError());
}
// 0:@K205< 107C 40==KE M:A?5@B0
DB::Close();
}
// !B@>:0 8=8F80;870F88 3@C??K AB@0B5389
string groupParams = NULL;
// 1I55 :>;8G5AB2> AB@0B5389 2 3@C??5
int totalStrategies = ArraySize(params);
// A;8 AB@0B5388 5ABL, B>
if(totalStrategies > 0) {
// !>548=O5< 8E AB@>:8 8=8F80;870F88 G5@57 70?OBCN
JOIN(params, groupParams, ",");
// !>740Q< AB@>:C 8=8F80;870F88 3@C??K AB@0B5389
groupParams = StringFormat("class CVirtualStrategyGroup([%s], %.5f)",
groupParams,
totalStrategies);
}
// >72@0I05< AB@>:C 8=8F80;870F88 3@C??K AB@0B5389
return groupParams;
}
//+------------------------------------------------------------------+
//| <O D09;0 A 107>9 40==KE M:A?5@B0 |
//+------------------------------------------------------------------+
string CVirtualAdvisor::FileName(string p_name, ulong p_magic = 1) {
return StringFormat("%s-%d%s.db.sqlite",
(p_name != "" ? p_name : "Expert"),
p_magic,
(MQLInfoInteger(MQL_TESTER) ? ".test" : "")
);
}
//+------------------------------------------------------------------+