Adwizard/Virtual/VirtualCloseManager.mqh

287 lines
22 KiB
MQL5
Raw Permalink Normal View History

<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| VirtualCloseManager.mqh |
//| Copyright 2022-2025, Yuriy Bykov |
//| https://www.mql5.com/ru/users/antekov |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022-2025, Yuriy Bykov"
#property link "https://www.mql5.com/ru/users/antekov"
#property version "1.00"
class CVirtualAdvisor;
#include "../Database/Storage.mqh"
// >7<>6=K5 A>AB>O=8O <5=5465@0 70:@KB8O
enum ENUM_CM_STATE {
2025-07-03 12:11:24 +03:00
CM_STATE_OK, // 8<8BK =5 ?@52KH5=K (=>@<0;L=>5 A>AB>O=85)
CM_STATE_LOSS, // @52KH5= >1I89 C1KB>:
2025-06-20 22:14:57 +03:00
CM_STATE_PROFIT, // >AB83=CB0 >1I0O ?@81K;L
CM_STATE_TRAIL_PROFIT // "@59;8=3 ?@81K;8
};
2025-06-20 22:14:57 +03:00
// >7<>6=K5 A?>A>1K @0AGQB0 >1I53> C1KB:0
enum ENUM_CM_CALC_LOSS {
2025-07-03 12:11:24 +03:00
CM_CALC_LOSS_MONEY_BB, // [$] Fixed Money
CM_CALC_LOSS_PERCENT_BB, // [%] of Base Balance
};
// >7<>6=K5 A?>A>1K @0AGQB0 >1I59 ?@81K;8
2025-06-20 22:14:57 +03:00
enum ENUM_CM_CALC_PROFIT {
2025-07-03 12:11:24 +03:00
CM_CALC_PROFIT_MONEY_BB, // [$] Fixed Money
CM_CALC_PROFIT_PERCENT_BB, // [%] of Base Balance
};
//+------------------------------------------------------------------+
//| ;0AA <5=5465@0 70:@KB8O (D8:A0F88 ?@81K;8 8 C1KB:>2) |
//+------------------------------------------------------------------+
class CVirtualCloseManager : public CFactorable {
protected:
// A=>2=K5 ?0@0<5B@K :>=AB@C:B>@0
double m_baseBalance; // 07>2K9 10;0=A
2025-07-03 12:11:24 +03:00
ENUM_CM_CALC_LOSS m_calcLossLimit; // !?>A>1 @0AGQB0 <0:A8<0;L=>3> >1I53> C1KB:0
double m_maxLossLimit; // 0@0<5B@ @0AGQB0 <0:A8<0;L=>3> >1I53> C1KB:0
2025-07-03 12:11:24 +03:00
ENUM_CM_CALC_PROFIT m_calcProfitLimit; // !?>A>1 @0AGQB0 <0:A8<0;L=>9 >1I59 ?@81K;8
double m_maxProfitLimit; // 0@0<5B@ @0AGQB0 <0:A8<0;L=>9 >1I59 ?@81K;8
2025-07-03 12:11:24 +03:00
CVirtualAdvisor* m_expert; // #:070B5;L =0 >1J5:B M:A?5@B0
// "5:CI55 A>AB>O=85
ENUM_CM_STATE m_state; // !>AB>O=85
// 1=>2;O5<K5 7=0G5=8O
double m_balance; // "5:CI89 10;0=A
double m_equity; // "5:CI85 A@54AB20
2025-07-03 12:11:24 +03:00
double m_profit; // "5:CI0O ?;020NI0O ?@81K;L
double m_overallProfit; // "5:CI0O >1I0O ?@81K;L >B=>A8B5;L=> 107>2>3> 10;0=A0
2025-06-20 22:14:57 +03:00
// 0I8IQ==K5 <5B>4K
2025-07-03 12:11:24 +03:00
double LossMoney(); // 0:A8<0;L=K9 >1I89 C1KB>:
double ProfitMoney(); // 0:A8<0;L=0O ?@81K;L
2025-07-03 12:11:24 +03:00
void UpdateProfit(); // 1=>2;5=85 B5:CI8E 7=0G5=89 ?@81K;8
void CheckLimits(); // @>25@:0 4>AB865=8O 4>?CAB8<KE C@>2=59 ?@81K;8/C1KB:0
CVirtualCloseManager(string p_params); // 0:@KBK9 :>=AB@C:B>@
public:
2025-07-03 12:11:24 +03:00
STATIC_CONSTRUCTOR(CVirtualCloseManager); // !B0B8G5A:89 <5B>4 A>740=8O >1J5:B0
2025-07-06 18:34:20 +03:00
virtual void Tick(); // 1@01>B:0 B8:0 2 <5=5465@5 70:@KB8O
2025-07-03 12:11:24 +03:00
virtual string Text(); // =D>@<0F8O > B5:CI5< A>AB>O=88
// @82O7:0 M:A?5@B0 : <5=5465@C 70:@KB8O
void Expert(CVirtualAdvisor* p_expert);
virtual bool Save(); // !>E@0=5=85 A>AB>O=8O
virtual bool Load(); // 03@C7:0 A>AB>O=8O
virtual string operator~() override; // @5>1@07>20=85 >1J5:B0 2 AB@>:C
};
2025-07-03 12:11:24 +03:00
REGISTER_FACTORABLE_CLASS(CVirtualCloseManager); // 538AB@0F8O =>2>3> ?>B><:0 CFactorable
//+------------------------------------------------------------------+
//| >=AB@C:B>@ |
//+------------------------------------------------------------------+
CVirtualCloseManager::CVirtualCloseManager(string p_params) {
// 0?><8=05< AB@>:C 8=8F80;870F88
m_params = p_params;
// '8B05< AB@>:C 8=8F80;870F88 8 CAB0=02;8205< 7=0G5=8O A2>9AB2
m_isActive = (bool) ReadLong(p_params);
m_baseBalance = ReadDouble(p_params);
2025-06-20 22:14:57 +03:00
m_calcLossLimit = (ENUM_CM_CALC_LOSS) ReadLong(p_params);
m_maxLossLimit = ReadDouble(p_params);
m_calcProfitLimit = (ENUM_CM_CALC_PROFIT) ReadLong(p_params);
m_maxProfitLimit = ReadDouble(p_params);
2025-07-03 12:11:24 +03:00
// #AB0=02;8205< A>AB>O=85: 8<8BK =5 ?@52KH5=K
m_state = CM_STATE_OK;
2025-07-06 18:34:20 +03:00
// 1=>2;O5< B5:CI85 7=0G5=8O ?@81K;8
2025-06-20 22:14:57 +03:00
UpdateProfit();
// >@@5:B8@C5< 107>2K9 10;0=A, 5A;8 >= =5 7040=
if(m_baseBalance == 0) {
m_baseBalance = m_balance;
}
}
//+------------------------------------------------------------------+
//| 1@01>B:0 B8:0 2 @8A:-<5=5465@5 |
//+------------------------------------------------------------------+
void CVirtualCloseManager::Tick() {
// A;8 @8A:-<5=5465@ =50:B825=, B> 2KE>48<
if(!m_isActive) {
return;
}
// 1=>2;O5< B5:CI85 7=0G5=8O ?@81K;8
UpdateProfit();
2025-07-03 12:11:24 +03:00
// A;8 <5=5465@ 2 A>AB>O=88 B@59;8=30, B>
2025-06-20 22:14:57 +03:00
if(m_state == CM_STATE_TRAIL_PROFIT) {
2025-07-03 12:11:24 +03:00
// >:0 ?@>AB> 1C45< A@07C D8:A8@>20BL ?@81K;L,
// ?5@52>4O <5=5465@ 2 A>>B25BA2CNI55 A>AB>O=85
2025-06-20 22:14:57 +03:00
if(true) {
m_state = CM_STATE_PROFIT;
}
}
2025-07-03 12:11:24 +03:00
// A;8 <5=5465@ 2 =>@<0;L=>< A>AB>O=88, B>
2025-06-20 22:14:57 +03:00
if(m_state == CM_STATE_OK) {
2025-07-03 12:11:24 +03:00
// @>25@O5< ?@52KH5=85 ?@545;>2 C1KB:0 8 ?@81K;8
2025-06-20 22:14:57 +03:00
CheckLimits();
}
2025-07-03 12:11:24 +03:00
// A;8 <5=5465@ 2 A>AB>O=88 4>AB83=CB>3> C1KB:0 8;8 ?@81K;8, B>
2025-06-20 22:14:57 +03:00
if(m_state == CM_STATE_LOSS || m_state == CM_STATE_PROFIT) {
// 0:@K205< 2A5 ?>78F88
m_expert.Close();
2025-07-03 12:11:24 +03:00
// A;8 2A5 ?>78F88 70:@KBK, B>
2025-06-20 22:14:57 +03:00
if(PositionsTotal() == 0) {
2025-07-03 12:11:24 +03:00
// 5@5E>48< 2 =>@<0;L=>5 A>AB>O=85
2025-06-20 22:14:57 +03:00
m_state = CM_STATE_OK;
2025-07-03 12:11:24 +03:00
// 1=>2;O5< 7=0G5=85 107>2>3> 10;0=A0
2025-06-20 22:14:57 +03:00
m_baseBalance = m_balance;
} else {
// 4Q< 70:@KB8O 2A5E ?>78F89
}
2025-07-03 12:11:24 +03:00
// !>E@0=O5< A>AB>O=85 M:A?5@B0
2025-06-20 22:14:57 +03:00
m_expert.Save();
}
}
//+------------------------------------------------------------------+
2025-07-03 12:11:24 +03:00
//| =D>@<0F8O > B5:CI5< A>AB>O=88 |
//+------------------------------------------------------------------+
string CVirtualCloseManager::Text() {
string s = "=== Close Manager ===\n";
2025-06-20 22:14:57 +03:00
s += StringFormat("BL: %8.2f | Target: %8.2f (%8.2f)\n",
m_baseBalance,
m_baseBalance + ProfitMoney(),
m_baseBalance - LossMoney());
return s;
}
//+------------------------------------------------------------------+
2025-07-03 12:11:24 +03:00
//| @82O7:0 M:A?5@B0 : <5=5465@C 70:@KB8O |
//+------------------------------------------------------------------+
void CVirtualCloseManager::Expert(CVirtualAdvisor* p_expert) {
m_expert = p_expert;
}
//+------------------------------------------------------------------+
//| !>E@0=5=85 A>AB>O=8O |
//+------------------------------------------------------------------+
bool CVirtualCloseManager::Save() {
CStorage::Set("CVirtualCloseManager::m_state", m_state);
CStorage::Set("CVirtualCloseManager::m_baseBalance", m_baseBalance);
return true;
}
//+------------------------------------------------------------------+
//| 03@C7:0 A>AB>O=8O |
//+------------------------------------------------------------------+
bool CVirtualCloseManager::Load() {
bool res = true;
res &= CStorage::Get("CVirtualCloseManager::m_state", m_state);
res &= CStorage::Get("CVirtualCloseManager::m_baseBalance", m_baseBalance);
return res;
}
//+------------------------------------------------------------------+
//| 0:A8<0;L=K9 >1I89 C1KB>: |
//+------------------------------------------------------------------+
2025-06-20 22:14:57 +03:00
double CVirtualCloseManager::LossMoney() {
if(m_calcLossLimit == CM_CALC_LOSS_PERCENT_BB) {
// ;O 7040==>3> ?@>F5=B0 >B 107>2>3> 10;0=A0 2KG8A;O5< 53>
2025-06-20 22:14:57 +03:00
return m_baseBalance * m_maxLossLimit / 100;
} else {
// ;O D8:A8@>20==>3> 7=0G5=8O ?@>AB> 2>72@0I05< 53>
2025-06-20 22:14:57 +03:00
// CM_CALC_LOSS_MONEY_BB
return m_maxLossLimit;
}
}
//+------------------------------------------------------------------+
2025-06-20 22:14:57 +03:00
//| 0:A8<0;L=0O >1I0O ?@81K;L |
//+------------------------------------------------------------------+
2025-06-20 22:14:57 +03:00
double CVirtualCloseManager::ProfitMoney() {
if(m_calcProfitLimit == CM_CALC_PROFIT_PERCENT_BB) {
// ;O 7040==>3> ?@>F5=B0 >B 107>2>3> 10;0=A0 2KG8A;O5< 53>
2025-06-20 22:14:57 +03:00
return m_baseBalance * m_maxProfitLimit / 100;
} else {
// ;O D8:A8@>20==>3> 7=0G5=8O ?@>AB> 2>72@0I05< 53>
2025-06-20 22:14:57 +03:00
// CM_CALC_PROFIT_MONEY_BB
return m_maxProfitLimit;
}
}
//+------------------------------------------------------------------+
//| 1=>2;5=85 B5:CI8E 7=0G5=89 ?@81K;8 |
//+------------------------------------------------------------------+
void CVirtualCloseManager::UpdateProfit() {
// "5:CI85 A@54AB20
m_equity = AccountInfoDouble(ACCOUNT_EQUITY);
// "5:CI89 10;0=A
m_balance = AccountInfoDouble(ACCOUNT_BALANCE);
2025-07-03 12:11:24 +03:00
// "5:CI0O ?;020NI0O ?@81K;L
m_profit = m_equity - m_balance;
// "5:CI0O >1I0O ?@81K;L >B=>A8B5;L=> 107>2>3> 10;0=A0
m_overallProfit = m_equity - m_baseBalance;
// 07 2 G0A 2K2>48< 7=0G5=8O 2 ;>3
if(IsNewBar(Symbol(), PERIOD_H1)) {
2025-06-20 22:14:57 +03:00
PrintFormat(__FUNCTION__" | Profit = %.2f | Overall = %.2f",
m_profit, m_overallProfit);
}
}
//+------------------------------------------------------------------+
//| @>25@:0 ;8<8B>2 C1KB:0 |
//+------------------------------------------------------------------+
void CVirtualCloseManager::CheckLimits() {
2025-07-03 12:11:24 +03:00
// A;8 4>AB83=CB >1I89 C1KB>:
2025-06-20 22:14:57 +03:00
if(m_overallProfit <= -LossMoney()) {
// #AB0=02;8205< @8A:-<5=5465@ 2 A>AB>O=85 4>AB83=CB>3> >1I53> C1KB:0
m_state = CM_STATE_LOSS;
2025-06-20 22:14:57 +03:00
PrintFormat(__FUNCTION__" | CLOSE LOSS Profit = %.2f | OverallProfit = %.2f (%.2f)",
m_profit, m_overallProfit, -LossMoney());
}
2025-06-20 22:14:57 +03:00
// A;8 4>AB83=CB >1I89 C1KB>: 8 ?>78F88 5IQ >B:@KBK
2025-07-03 12:11:24 +03:00
else if(m_overallProfit >= ProfitMoney()) {
// #AB0=02;8205< @8A:-<5=5465@ 2 A>AB>O=85 4>AB83=CB>9 >1I59 ?@81K;8
2025-06-20 22:14:57 +03:00
m_state = CM_STATE_PROFIT;
PrintFormat(__FUNCTION__" | CLOSE PROFIT Profit = %.2f | OverallProfit = %.2f (%.2f)",
m_profit, m_overallProfit, ProfitMoney());
}
}
//+------------------------------------------------------------------+
//| @5>1@07>20=85 >1J5:B0 2 AB@>:C |
//+------------------------------------------------------------------+
string CVirtualCloseManager::operator~() {
return StringFormat("%s(%s)", typename(this), m_params);
}
//+------------------------------------------------------------------+