Project_N_1/Include/General_class_.mqh
super.admin fca2fc1d82 convert
2025-05-30 16:18:18 +02:00

443 lines
36 KiB
MQL5

//+------------------------------------------------------------------+
//| ProjectName |
//| Copyright 2020, CompanyName |
//| http://www.companyname.net |
//+------------------------------------------------------------------+
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
#include <Trade\SymbolInfo.mqh>
#include <Trade\AccountInfo.mqh>
#include <Trade\DealInfo.mqh>
#include <Trade\OrderInfo.mqh>
#include <Expert\Money\MoneyFixedMargin.mqh>
CTrade a_trade;
CPositionInfo a_position;
CSymbolInfo a_symbol;
CAccountInfo a_accauntInfo;
CDealInfo a_deal;
COrderInfo a_order;
//--- Объявляем структуры, которые будут использоваться для торговли
MqlTick latest_price; // Будет использоваться для текущих котировок
MqlTradeRequest mrequest; // Будет использоваться для отсылки торговых запросов
MqlTradeResult mresult; // Будет использоваться для получения результатов выполнения торговых запросов
MqlRates mrate[]; // Будет содержать цены, объемы и спред для каждого бара
sinput int Magic = 0;
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
class CGeneral_class
{
private:
public:
CGeneral_class();
~CGeneral_class();
double LotSize(int _SL, double MR);
bool OpenBuyPosition(double volume,double price, double StopLoss_, double TP_);
bool OpenSellPosition(double volume,double price, double StopLoss_, double TP_);
int CheckOpen(int &ob, int &os, datetime & t_ob, datetime & t_os);
void CheckVolume(double &Volume_current_sell,double &Volume_current_buy);
void CloseBuy();
void CloseSell();
void CloseBuyPartial(string Symbol_, int x);
void CloseSellPartial(string Symbol_, int x);
bool isNewBar(ENUM_TIMEFRAMES per);
string st5(double x);
bool CheckTimePeriod(string Start_Time, string End_Time);
bool SpreadFilter(int bars, int pauseTime, int x);
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CGeneral_class::CGeneral_class()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CGeneral_class::~CGeneral_class()
{
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------------+
//+- Расчет лота в зависимости от расстояния до StopLoss +//
//+------------------------------------------------------------------------+
double CGeneral_class::LotSize(int _SL, double MR)// SL-StopLoss MR-MaxRisk в % от баланса
{
if(_SL == 0)
return(0); // исключение деления на ноль
double Free = AccountInfoDouble(ACCOUNT_BALANCE);
double LotVal = SymbolInfoDouble(_Symbol, SYMBOL_TRADE_TICK_VALUE); //стоимость 1 пункта 1 лота
double Min_Lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
double Max_Lot = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MAX);
double Step = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_STEP);
double Lot = MathFloor((Free * MR / 100) / (_SL * LotVal) / Step) * Step;
if(Lot < Min_Lot)
Lot = Min_Lot;
if(Lot > Max_Lot)
Lot = Max_Lot;
return(Lot);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CGeneral_class :: OpenSellPosition(double volume,double price, double StopLoss_, double TP_)
{
ZeroMemory(mrequest);
ZeroMemory(mresult);
mrequest.action = TRADE_ACTION_DEAL; // немедленное исполнение
mrequest.price = NormalizeDouble(price, _Digits); // последняя цена Bid
mrequest.sl = StopLoss_; // Stop Loss
mrequest.tp = TP_ ;// NormalizeDouble(latest_price.bid - TP * _Point, _Digits); // Take Profit
mrequest.symbol = _Symbol; // символ
mrequest.volume = volume; // количество лотов для торговли
mrequest.magic = Magic; // Magic Number
mrequest.type = ORDER_TYPE_SELL; // ордер на продажу
mrequest.type_filling = ORDER_FILLING_FOK; // тип исполнения ордера - все или ничего
mrequest.deviation = 100; // проскальзывание от текущей цены
//--- отсылаем ордер
OrderSend(mrequest, mresult);
// анализируем код возврата торгового сервера
if(mresult.retcode == 10009 || mresult.retcode == 10008) //Request is completed or order placed
{
Print("Ордер Sell успешно помещен, тикет ордера #:", mresult.order, "!!");
return true;
}
else
{
SendMail(_Symbol + " Запрос на установку ордера Buy не выполнен. код ошибки: " + GetLastError(),
_Symbol + " result retcode: " + mresult.retcode + "result.deal: " + mresult.deal + "result.order " + mresult.order + "Период: " + GetNameTF());
Print("Sell -> false. Result Retcode: ",+ mresult.retcode + " result.deal: " + mresult.deal + "result.order " + mresult.order + "Период: " + GetNameTF());
return false;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CGeneral_class :: OpenBuyPosition(double volume, double price, double StopLoss_, double TP_)
{
ZeroMemory(mrequest);
ZeroMemory(mresult);
mrequest.action = TRADE_ACTION_DEAL; // немедленное исполнение
mrequest.price = NormalizeDouble(price, _Digits); // последняя цена Bid
mrequest.sl = StopLoss_; // Stop Loss
mrequest.tp = TP_;//NormalizeDouble(latest_price.ask + TP * _Point, _Digits); // Take Profit
mrequest.symbol = _Symbol; // символ
mrequest.volume = volume; // количество лотов для торговли
mrequest.magic = Magic; // Magic Number
mrequest.type = ORDER_TYPE_BUY; // ордер на продажу
mrequest.type_filling = ORDER_FILLING_FOK; // тип исполнения ордера - все или ничего
mrequest.deviation = 100; // проскальзывание от текущей цены
//--- отсылаем ордер
OrderSend(mrequest, mresult);
// анализируем код возврата торгового сервера
if(mresult.retcode == 10009 || mresult.retcode == 10008) //Request is completed or order placed
{
return true;
Print("Ордер Sell успешно помещен, тикет ордера #:", mresult.order, "!!");
}
else
{
SendMail(_Symbol + " Запрос на установку ордера Buy не выполнен. код ошибки: " + GetLastError(),
_Symbol + " result retcode: " + mresult.retcode + "result.deal: " + mresult.deal + "result.order " + mresult.order + "Период: " + GetNameTF());
Print("Buy -> false. Result Retcode: ",+ mresult.retcode + " result.deal: " + mresult.deal + "result.order " + mresult.order + "Период: " + GetNameTF());
return false;
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CGeneral_class :: CheckOpen(int &ob, int &os, datetime & t_ob, datetime & t_os)
{
ob = 0;
os = 0;
int res = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
a_position.SelectByIndex(i);
if(a_position.Magic() == Magic && a_position.Symbol() == _Symbol)
{
if(a_position.PositionType() == POSITION_TYPE_BUY)
{
t_ob = a_position.Time();
ob++;
}
if(a_position.PositionType() == POSITION_TYPE_SELL)
{
t_os = a_position.Time();
os++;
}
}
}
res = ob + os;
return res;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
//double Volume_current_sell;
//double Volume_current_buy;
void CGeneral_class :: CheckVolume(double &Volume_current_sell,double &Volume_current_buy)
{
Volume_current_sell = 0;
Volume_current_buy = 0;
for(int i = PositionsTotal()-1; i >= 0; i--)
{
a_position.SelectByIndex(i);
if(a_position.Magic() == Magic && a_position.Symbol() == _Symbol)
{
if(a_position.PositionType() == POSITION_TYPE_BUY)
{
Volume_current_buy += PositionGetDouble(POSITION_VOLUME);
}
if(a_position.PositionType() == POSITION_TYPE_SELL)
{
Volume_current_sell += PositionGetDouble(POSITION_VOLUME);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CGeneral_class :: CloseSell()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
a_position.SelectByIndex(i);
if(a_position.Magic() == Magic && a_position.Symbol() == _Symbol)
{
if(a_position.PositionType() == POSITION_TYPE_SELL)
a_trade.PositionClose(a_position.Ticket());
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CGeneral_class :: CloseBuy()
{
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
a_position.SelectByIndex(i);
if(a_position.Magic() == Magic && a_position.Symbol() == _Symbol)
{
if(a_position.PositionType() == POSITION_TYPE_BUY)
{
int o = a_trade.PositionClose(a_position.Ticket());
if(o <= 0)
Print("<--- CloseBuy ", _LastError, " ", __LINE__);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CGeneral_class :: CloseBuyPartial(string Symbol_, int x)
{
double Volume_current_buy = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
a_position.SelectByIndex(i);
if(a_position.Magic() == Magic && a_position.Symbol() == Symbol_)
{
if(a_position.PositionType() == POSITION_TYPE_BUY)
{
Volume_current_buy = PositionGetDouble(POSITION_VOLUME);
double Lot = NormalizeDouble(Volume_current_buy/x, 2);
bool o = a_trade.PositionClosePartial(a_position.Ticket(),Lot,-1);
if(o == false)
Print("<--- CloseBuy ", _LastError, " ", __LINE__);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CGeneral_class ::CloseSellPartial(string Symbol_, int x)
{
double Volume_current_sell = 0;
for(int i = PositionsTotal() - 1; i >= 0; i--)
{
a_position.SelectByIndex(i);
if(a_position.Magic() == Magic && a_position.Symbol() == Symbol_)
{
if(a_position.PositionType() == POSITION_TYPE_SELL)
{
Volume_current_sell = PositionGetDouble(POSITION_VOLUME);
double Lot = NormalizeDouble(Volume_current_sell/x, 2);
bool o = a_trade.PositionClosePartial(a_position.Ticket(),Lot,-1);
if(o == false)
Print("<--- CloseBuy ", _LastError, " ", __LINE__);
}
}
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CGeneral_class :: isNewBar(ENUM_TIMEFRAMES per)
{
//--- в статической переменной будем помнить время открытия последнего бара
static datetime last_time = 0;
//--- текущее время
datetime lastbar_time = SeriesInfoInteger(Symbol(), per, SERIES_LASTBAR_DATE);
//--- если это первый вызов функции
if(last_time == 0)
{
//--- установим время и выйдем
last_time = lastbar_time;
return(false);
}
//--- если время отличается
if(last_time != lastbar_time)
{
//--- запомним время и вернем true
last_time = lastbar_time;
return(true);
}
//--- дошли до этого места - значит бар не новый, вернем false
return(false);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string CGeneral_class :: st5(double x)
{
return DoubleToString(x, _Digits);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CGeneral_class :: CheckTimePeriod(string Start_Time, string End_Time)
{
datetime currentTime = TimeCurrent();
datetime start_time = StringToTime(Start_Time);
datetime end_time = End_Time > Start_Time ? StringToTime(End_Time) : StringToTime(StringToTime(End_Time) + 3600 * 24);
//+------------------------------------------------------------------+
// Такой вид конструкции называется тернарной операцией. Это более красивая форма записи кода ниже:
//
//if (End_Time > Start_Time)
//{
// end_time = StringToTime(End_Time)
//}
//else
//{
// end_time = StringToTime(StringToTime(End_Time) + 3600 * 24)
//}
// Структура тернарной операции такая: if() ? valueIfTrue : valueIfFalse;
//
// Если требуется выполнить несколько операций в результате исхода, то используется if.
// Т.е так не получится
// end_time = End_Time > Start_Time ? StringToTime(End_Time) *тут еще какая то операция* : StringToTime(StringToTime(End_Time) + 3600 * 24) *или тут*;
//+------------------------------------------------------------------+
//Print("Current time: ", currentTime);
//Print("Start time: ", start_time);
//Print("End time: ", end_time);
return currentTime > start_time && currentTime < end_time;
// Аналогично этому:
// if(currentTime > start_time && currentTime < end_time)
// {
// return true;
// }
// return false;
}
//+------------------------------------------------------------------+
//|Проверяем размах спреда |
//+------------------------------------------------------------------+
bool CGeneral_class :: SpreadFilter(int bars, int pauseTime, int x)
{
double spread = 0;
int values[];
int count = CopySpread(_Symbol, PERIOD_H1, 0, bars, values);
for(int i = 0; i < count; i++)
{
spread += values[i];
}
double middleSpread = spread / bars * SymbolInfoDouble(_Symbol, SYMBOL_POINT);
double currentSpread = SymbolInfoInteger(_Symbol, SYMBOL_SPREAD);
datetime lastAllowedSpreadTime = 0;
// Если спред большой, то запоминаем текущее время и выжидаем некоторую паузу, после которой он может уменьшится.
if(currentSpread > (middleSpread+x))// x - это погрешность, которую мы учитываем
{
lastAllowedSpreadTime = TimeCurrent();
return false;
}
else
{
if(TimeCurrent() < lastAllowedSpreadTime + pauseTime)
return false;
lastAllowedSpreadTime = 0;
return true;
}
}
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string GetNameTF(int TimeFrame = 0)
{
if(TimeFrame == 0)
TimeFrame = Period();
switch(TimeFrame)
{
case PERIOD_M1:
return("M1");
case PERIOD_M5:
return("M5");
case PERIOD_M10:
return("M10");
case PERIOD_M15:
return("M15");
case PERIOD_M20:
return("M20");
case PERIOD_M30:
return("M30");
case PERIOD_H1:
return("H1");
case PERIOD_H2:
return("H2");
case PERIOD_H4:
return("H4");
case PERIOD_D1:
return("Daily");
case PERIOD_W1:
return("Weekly");
case PERIOD_MN1:
return("Monthly");
default:
return("Unknown Period");
}
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+