Adwizard/Database/Storage.mqh

332 lines
23 KiB
MQL5
Raw Permalink Normal View History

2025-04-11 13:28:40 +03:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Storage.mqh |
//| Copyright 2024, Yuriy Bykov |
//| https://www.mql5.com/ru/users/antekov |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, Yuriy Bykov"
#property link "https://www.mql5.com/ru/users/antekov"
#property version "1.01"
#include "Database.mqh"
#include "../Base/Factorable.mqh"
#include "../Virtual/VirtualOrder.mqh"
//+------------------------------------------------------------------+
//| ;0AA 4;O @01>BK A 107>9 40==KE M:A?5@B0 2 2845 |
//| E@0=8;8I0 Key-Value 4;O A2>9AB2 8 28@BC0;L=KE ?>78F89 |
//+------------------------------------------------------------------+
class CStorage {
protected:
static bool s_res; // 57C;LB0B 2A5E >?5@0F89 GB5=8O/70?8A8 107K 40==KE
public:
// >4:;NG5=85 : 1075 40==KE M:A?5@B0
static bool Connect(string p_fileName);
// 0:@KB85 ?>4:;NG5=8O : 1075 40==KE
static void Close();
// G8AB:0 40==KE
static void Clear();
// !>E@0=5=85 28@BC0;L=>3> >@45@0/?>78F88
static void Set(int i, CVirtualOrder* order);
// !>E@0=5=85 >4=>3> 7=0G5=8O ?@>872>;L=>3> ?@>AB>3> B8?0
template<typename T>
static void Set(string key, const T &value);
// !>E@0=5=85 <0AA820 7=0G5=89 ?@>872>;L=>3> ?@>AB>3> B8?0
template<typename T>
static void Set(string key, const T &values[]);
// >;CG5=85 7=0G5=8O 2 2845 AB@>:8 ?> 7040==><C :;NGC
static string Get(string key);
// >;CG5=85 <0AA820 28@BC0;L=KE >@45@>2/?>78F89 ?> 7040==><C E5HC AB@0B5388
static bool Get(string key, CVirtualOrder* &orders[]);
// >;CG5=85 7=0G5=8O ?> 7040==><C :;NGC 2 ?5@5<5==CN ?@>872>;L=>3> ?@>AB>3> B8?0
template<typename T>
static bool Get(string key, T &value);
// >;CG5=85 <0AA820 7=0G5=89 ?@>AB>3> B8?0 ?> 7040==><C :;NGC 2 ?5@5<5==CN
template<typename T>
static bool CStorage::Get(string key, T &values[]);
static bool CStorage::GetSymbols(string &symbols[]);
// 57C;LB0B >?5@0F89
static bool Res() {
return s_res;
}
};
// 57C;LB0B 2A5E >?5@0F89 GB5=8O/70?8A8 107K 40==KE
bool CStorage::s_res = true;
//+------------------------------------------------------------------+
//| >4:;NG5=85 : 1075 40==KE M:A?5@B0 |
//+------------------------------------------------------------------+
bool CStorage::Connect(string p_fileName) {
// >4:;NG05<AO : 1075 40==KE M:A?5@B0
if(DB::Connect(p_fileName, DB_TYPE_ADV)) {
// #AB0=02;8205<, GB> ?>:0 >H81>: =5B
s_res = true;
// 0G8=05< B@0=70:F8N
DatabaseTransactionBegin(DB::Id());
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| 0:@KB85 ?>4:;NG5=8O : 1075 40==KE |
//+------------------------------------------------------------------+
void CStorage::Close() {
// A;8 >H81>: =5B, B>
if(s_res) {
// >4B25@6405< B@0=70:F8N
DatabaseTransactionCommit(DB::Id());
} else {
// =0G5 B@0=70:F8N >B<5=O5<
DatabaseTransactionRollback(DB::Id());
}
// 0:@K205< A>548=5=85 A 107>9 40==KE
DB::Close();
}
//+------------------------------------------------------------------+
//| G8AB:0 40==KE |
//+------------------------------------------------------------------+
void CStorage::Clear() {
string query = "DELETE FROM storage;\n"
"DELETE FROM storage_orders;";
DB::Execute(query);
}
//+------------------------------------------------------------------+
//| !>E@0=5=85 28@BC0;L=>3> >@45@0/?>78F88 |
//+------------------------------------------------------------------+
void CStorage::Set(int i, CVirtualOrder* order) {
VirtualOrderStruct o; // !B@C:BC@0 4;O 8=D>@<0F88 > 28@BC0;L=>9 ?>78F88
order.Save(o); // 0?>;=O5< 5Q
// -:@0=8@C5< :02KG:8 2 :><<5=B0@88
StringReplace(o.comment, "'", "\\'");
// 0?@>A =0 A>E@0=5=85
string query = StringFormat("REPLACE INTO storage_orders VALUES("
"'%s',%d,%I64u,"
"'%s',%.2f,%d,%I64d,%f,%f,%f,%I64d,%f,%I64d,'%s',%f);",
order.Strategy().Hash(), i, o.ticket,
o.symbol, o.lot, o.type,
o.openTime, o.openPrice,
o.stopLoss, o.takeProfit,
o.closeTime, o.closePrice,
o.expiration, o.comment,
o.point);
// K?>;=O5< 70?@>A
s_res &= DatabaseExecute(DB::Id(), query);
if(!s_res) {
// !>>1I05< >1 >H81:5 ?@8 =5>1E>48<>AB8
PrintFormat(__FUNCTION__" | ERROR: Execution failed in DB [adv], query:\n"
"%s\n"
"error code = %d",
query, GetLastError());
}
}
//+------------------------------------------------------------------+
//| !>E@0=5=85 >4=>3> 7=0G5=8O ?@>872>;L=>3> ?@>AB>3> B8?0 |
//+------------------------------------------------------------------+
template<typename T>
void CStorage::Set(string key, const T &value) {
// -:@0=8@C5< A8<2>;K >48=0@=KE :02KG5: (?>:0 =5 <>6=> =5 8A?>;L7>20BL)
// StringReplace(key, "'", "\\'");
// StringReplace(value, "'", "\\'");
// 0?@>A =0 A>E@0=5=85 7=0G5=8O
string query = StringFormat("REPLACE INTO storage(key, value) VALUES('%s', '%s');",
key, (string) value);
// K?>;=O5< 70?@>A
s_res &= DatabaseExecute(DB::Id(), query);
if(!s_res) {
// !>>1I05< >1 >H81:5 ?@8 =5>1E>48<>AB8
PrintFormat(__FUNCTION__" | ERROR: Execution failed in DB [adv], query:\n"
"%s\n"
"error code = %d",
query, GetLastError());
}
}
//+------------------------------------------------------------------+
//| !>E@0=5=85 <0AA820 7=0G5=89 ?@>872>;L=>3> ?@>AB>3> B8?0 |
//+------------------------------------------------------------------+
template<typename T>
void CStorage::Set(string key, const T &values[]) {
string value = "";
// !>548=O5< 2A5 7=0G5=8O 87 <0AA820 2 >4=C AB@>:C G5@57 70?OBCN
JOIN(values, value, ",");
// !>E@0=O5< AB@>:C A 7040==K< :;NG><
Set(key, value);
}
//+------------------------------------------------------------------+
//| >;CG5=85 7=0G5=8O 2 2845 AB@>:8 ?> 7040==><C :;NGC |
//+------------------------------------------------------------------+
string CStorage::Get(string key) {
string value = NULL; // >72@0I05<>5 7=0G5=85
// 0?@>A =0 ?>;CG5=85 7=0G5=8O
string query = StringFormat("SELECT value FROM storage WHERE key='%s'", key);
// K?>;=O5< 70?@>A
int request = DatabasePrepare(DB::Id(), query);
// A;8 =5B >H81:8
if(request != INVALID_HANDLE) {
// '8B05< 40==K5 87 ?5@2>9 AB@>:8 @57C;LB0B0
DatabaseRead(request);
if(!DatabaseColumnText(request, 0, value)) {
s_res = false;
// !>>1I05< >1 >H81:5 ?@8 =5>1E>48<>AB8
PrintFormat(__FUNCTION__" | ERROR: Reading row in DB [adv] for request \n%s\n"
"failed with code %d",
query, GetLastError());
}
} else {
s_res = false;
// !>>1I05< >1 >H81:5 ?@8 =5>1E>48<>AB8
PrintFormat(__FUNCTION__" | ERROR: Request in DB [adv] \n%s\nfailed with code %d",
query, GetLastError());
}
return value;
}
//+------------------------------------------------------------------+
//| >;CG5=85 7=0G5=8O ?> 7040==><C :;NGC 2 ?5@5<5==CN |
//| ?@>872>;L=>3> ?@>AB>3> B8?0 |
//+------------------------------------------------------------------+
template<typename T>
bool CStorage::Get(string key, T &value) {
// >;CG05< 7=0G5=85 2 2845 AB@>:8
string res = Get(key);
// A;8 7=0G5=85 ?>;CG5=>
if(res != NULL) {
// @82>48< 53> : B8?C " 8 ?@8A208205< F5;52>9 ?5@5<5==>9
value = (T) res;
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| >;CG5=85 <0AA820 7=0G5=89 ?@>872>;L=>3> ?@>AB>3> B8?0 |
//+------------------------------------------------------------------+
template<typename T>
bool CStorage::Get(string key, T &values[]) {
string params = Get(key);
int n = ArraySize(values);
if(params != NULL) {
string parts[];
StringSplit(params, ',', parts);
FOREACH(parts) {
if(i < n) {
values[i] = (T) parts[i];
} else {
APPEND(values, (T) parts[i]);
}
}
return true;
}
return false;
}
//+------------------------------------------------------------------+
//| >;CG5=85 <0AA820 28@BC0;L=KE >@45@>2/?>78F89 |
//| ?> 7040==><C E5HC AB@0B5388 |
//+------------------------------------------------------------------+
bool CStorage::Get(string key, CVirtualOrder* &orders[]) {
// 0?@>A =0 ?>;CG5=85 40==KE > 28@BC0;L=KE ?>78F8OE
string query = StringFormat("SELECT * FROM storage_orders "
" WHERE strategy_hash = '%s' "
" ORDER BY strategy_index ASC;",
key);
// K?>;=O5< 70?@>A
int request = DatabasePrepare(DB::Id(), query);
// A;8 =5B >H81:8
if(request != INVALID_HANDLE) {
// !B@C:BC@0 4;O 8=D>@<0F88 > 28@BC0;L=>9 ?>78F88
VirtualOrderStruct row;
// '8B05< ?>AB@>G=> 40==K5 87 @57C;LB0B0 70?@>A0
while(DatabaseReadBind(request, row)) {
orders[row.strategyIndex].Load(row);
}
} else {
// 0?><8=05< >H81:C 8 A>>1I05< >1 =59 ?@8 =5>1E>48<>AB8
s_res = false;
PrintFormat(__FUNCTION__" | ERROR: Execution failed in DB [adv], query:\n"
"%s\n"
"error code = %d",
query, GetLastError());
}
return s_res;
}
//+------------------------------------------------------------------+
//| >;CG5=85 <0AA820 A8<2>;>02 28@BC0;L=KE >@45@>2/?>78F89 |
//+------------------------------------------------------------------+
bool CStorage::GetSymbols(string &symbols[]) {
// 0?@>A =0 ?>;CG5=85 40==KE > 28@BC0;L=KE ?>78F8OE
string query = StringFormat("SELECT symbol FROM storage_orders "
" WHERE symbol <> ''"
" GROUP BY symbol", "");
// K?>;=O5< 70?@>A
int request = DatabasePrepare(DB::Id(), query);
// A;8 =5B >H81:8
if(request != INVALID_HANDLE) {
// !B@C:BC@0 4;O 8=D>@<0F88 > 28@BC0;L=>9 ?>78F88
string symbol;
// '8B05< ?>AB@>G=> 40==K5 87 @57C;LB0B0 70?@>A0
while(DatabaseRead(request)) {
s_res &= DatabaseColumnText(request, 0, symbol);
APPEND(symbols, symbol);
}
} else {
// 0?><8=05< >H81:C 8 A>>1I05< >1 =59 ?@8 =5>1E>48<>AB8
s_res = false;
PrintFormat(__FUNCTION__" | ERROR: Execution failed in DB [adv], query:\n"
"%s\n"
"error code = %d",
query, GetLastError());
}
return s_res;
}
//+------------------------------------------------------------------+