DevSolve_DS_SDK_UnitTest/Engine.mqh
super.admin bcf2d970f1 convert
2025-05-30 14:49:27 +02:00

1547 lines
116 KiB
MQL5

//+------------------------------------------------------------------+
//| Engine.mqh |
//| Copyright 2024 - Dev.Solve LTDA |
//+------------------------------------------------------------------+
//--- includes
#include "ExpertTakeProfit.mqh"
#include "ExpertStopLoss.mqh"
#include "ExpertStrategy.mqh"
#include "ExpertMoney.mqh"
#include "EngineBase.mqh"
//+------------------------------------------------------------------+
//| Class CEngine |
//| Appointment: Class CEngine - general class for trading robots. |
//+------------------------------------------------------------------+
class CEngine : public CEngineBase
{
protected:
//--- global variables
MqlTradeRequest m_request; // trade request
MqlTradeCheckResult m_check_result; // trade check result
MqlTradeResult m_result; // trade result
datetime m_expiration; // time expiration order
ENUM_ORDER_TYPE_FILLING m_typefilling; // preenchimento da ordem
ulong m_last_ticket; // number of the last ticket
//--- general configs
double m_shift_points_order; // [ordem pendente] deslocar entrada em pontos
bool m_flag_tick; // flag para checagem barra a barra ou tick a tick
bool m_flag_tick_in; // flag para abertura de posição barra a barra ou tick a tick
bool m_flag_error_params; // flag de erro de parâmetros de inicialização de otimização
//---position sizing defined in EngineBase
//--- trading hours
int m_horaInicioAbertura; // Hora de Inicio de Abertura de Posições
int m_minutoInicioAbertura; // Minuto de Inicio de Abertura de Pisoções
int m_horaFimAbertura; // Hora de Encerramento de Abertura de Posições
int m_minutoFimAbertura; // Minuto de Encerramento de Abertura de Posições
int m_horaFimOrdens; // Hora para o fim de emissão de ordens
int m_minFimOrdens; // Minutos para fim de emissão de ordens
bool m_expirationorders; // Remover ordens pendentes no término de envio de ordens
//--- simple type hour
bool m_simple_hour_flag; // Usar horário simpplificado
ENUM_SIMPLE_TYPE_HOURS m_simple_hour; // Tipo de intervalo escolhido
//--- config swing trade
bool m_is_swing; // Verificar se é operação de Swing Trade
ENUM_TYPE_TRADE_CLOSING m_trade_closing; // Período de encerramento do Trade
datetime m_init_swing; // Início da operação
datetime m_end_swing; // Término da operação
bool m_close_trade; // Encerrar operação
//--- global variables
string m_expertname; // Nome do EA
double m_lote; // Quantidade de Contratos
ulong m_deviation; // Desvio máximo em pontos
bool m_status_pos; // Flag do estado da posição
bool m_status_order; // Flag do estado da ordem
bool m_status_expiration; // FLag do estado da expiração de ordens
bool m_status_trading_hours; // Flag do estado do horário de negociação
int m_max_orders; // Número máximo de ordens pendentes
ulong m_ticket_buy; // Tikect da última ordem de compra
ulong m_ticket_sell; // Ticket da última ordem de venda
int m_num_orders_buy; // Número de ordens de compra
int m_num_orders_sell; // Número de ordens de venda
//--- used objects
CTrade *m_trade; // trade object
CPositionInfo m_position; // position info object
COrderInfo m_order; // order info object
CDealInfo m_deal; // deal info object
CExpertMoney *m_money; // money object
CExpertStrategy *m_strategy; // strategy object
CExpertStopLoss *m_stoploss; // stop loss object
CExpertTakeProfit *m_takeprofit; // take profit object
//--- linear regression
CLinearRegressionFilter *m_LRFilter_Buy; // linear regression filter buy
CLinearRegressionFilter *m_LRFilter_Sell; // linear regression filter sell
bool m_LRFilter_Is_Usage; // fag of the use
public:
CEngine();
~CEngine();
//--- initialization
bool Init(string expert_name,string symbol,ENUM_TIMEFRAMES period,bool every_tick,ulong magic=0,double lot=0);
//--- initialization objects
virtual bool InitTrade(ulong magic,CTrade *trade=NULL);
virtual bool InitMoney(CExpertMoney *money=NULL);
virtual bool InitStrategy(CExpertStrategy *strategy=NULL);
virtual bool InitStopLoss(CExpertStopLoss *stoploss=NULL);
virtual bool InitTakeProfit(CExpertTakeProfit *takeprofit=NULL);
//--- initioalize linear regresseion filter
virtual bool InitLinearRegressionFilter(bool is_usage, string symbol, ENUM_TIMEFRAMES LinearRegressionFilter_TF, int PeriodoLinearRegressionFilter_,
ENUM_FILTER_LINEAR_REGRESSION_DIRECTION LinearRegressionDirection_, bool LinearRegressionFilterUseLocation_,
ENUM_FILTER_LINEAR_REGRESSION_LOCATION LinearRegressionLocation_Buy_,
ENUM_FILTER_LINEAR_REGRESSION_LOCATION LinearRegressionLocation_Sell_);
//--- method of verification of settings
virtual bool ValidationSettings(void);
virtual void SetErrorParams(bool value) { m_flag_error_params=value; };
virtual bool GetErrorParams(void) { return m_flag_error_params; };
//--- method of creating the collection filters
virtual bool InitFilters(CExpertFilter *_filters=NULL);
//--- method of creating the indicator and timeseries
virtual bool InitIndicators(CIndicators *indicators=NULL);
//--- initialization trade hours and methods of hours
bool InitEngineHours(int h_ini,int min_ini,int h_end,int min_end);
bool GetHours(ENUM_TYPE_HOURS ini, ENUM_TYPE_HOURS orders, ENUM_TYPE_HOURS end);
void SetSimpleHour(bool value) { m_simple_hour_flag=value; };
void SetTypeSimpleHour(ENUM_SIMPLE_TYPE_HOURS value) { m_simple_hour=value; };
//--- manange close positions
void GetTypeClosing(ENUM_TYPE_TRADE_CLOSING value) { m_trade_closing=value; };
//--- get current lot
double GetCurrentLot(void) { return(m_lote); };
//--- deinitialization
virtual void Deinit(void);
//--- methods of setting adjustable parameters
int MaxOrders(void) const { return(m_max_orders); }
void MaxOrders(int value) { m_max_orders=value; }
ulong Deviation(void) const { return(m_deviation); }
void Deviation(ulong value) { m_deviation=value; }
bool ExpirationOrders(void) const { return(m_expirationorders); }
void ExpirationOrders(bool value) { m_expirationorders=value; }
double ShiftOrderPoints(void) const { return(m_shift_points_order); }
void ShiftOrderPoints(double value) { m_shift_points_order=value; }
void SetTickFlag(bool value) { m_flag_tick=value; }
void SetTickFlagIn(bool value) { m_flag_tick_in=value; }
//--- event handlers
virtual void OnTick(void);
virtual void OnTradeTransaction(const MqlTradeTransaction& trans,const MqlTradeRequest& request,const MqlTradeResult& result);
virtual double OnTester(void);
protected:
//--- deinitialization
virtual void DeinitTrade(void);
virtual void DeinitMoney(void);
virtual void DeinitStrategy(void);
virtual void DeinitStopLoss(void);
virtual void DeinitTakeProfit(void);
virtual void DeinitIndicators(void);
virtual void DeinitFilters(void);
//--- refreshing elements
virtual bool Refresh(void);
//--- trading hours
bool CheckTradingHours(void);
bool CheckExpirationOrders(void);
bool IsClosingTime(void);
bool IsCloseMarket(void);
bool CloseTrade(void);
//--- select elements trade
virtual bool SelectPosition(void);
virtual bool SelectOrder(void);
//--- initial checking
virtual bool InitChecking(void);
//--- main method
virtual bool Processing(void);
//--- check condition for open position
virtual bool IsEntryIn(bool flag);
virtual bool IsEntryOut(bool flag);
//--- trade open position check
virtual bool CheckOpen(void);
virtual bool CheckOpenLong(void);
virtual bool CheckOpenShort(void);
//--- order check
void ZeroRequest(void);
//--- trade open positions prcessing
virtual bool OpenLong(double price,double sl,double tp);
virtual bool OpenShort(double price,double sl,double tp);
//--- methos of stop loss
virtual bool CheckStopLoss(void);
virtual bool CheckStopLossLong(void);
virtual bool CheckStopLossShort(void);
virtual bool StopLoss(double sl,double tp);
//--- methos of take profit
virtual bool CheckTakeProfit(void);
virtual bool CheckTakeProfitLong(void);
virtual bool CheckTakeProfitShort(void);
virtual bool TakeProfit(double sl,double tp);
//--- methos of trailing orders
virtual bool CheckTrailingOrder(void) { return(false); };
virtual bool CheckTrailingOrderLong(void);
virtual bool CheckTrailingOrderShort(void);
virtual bool TrailingOrder(void);
virtual bool TrailingOrderLong(double price,datetime expiration);
virtual bool TrailingOrderShort(double price,datetime expiration);
//--- common protect functions
virtual void SetMarginMode(void) { m_margin_mode=(ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE); }
virtual bool IsHedging(void) const { return(m_margin_mode==ACCOUNT_MARGIN_MODE_RETAIL_HEDGING); }
//--- auxiliary functions
virtual int NumPendingOrdersBuy(void) { return(m_num_orders_buy); };
virtual int NumPendingOrdersSell(void) { return(m_num_orders_sell); };
virtual bool Close(void);
virtual bool CloseByTicket(ulong ticket);
virtual bool DeleteOrders(void);
virtual bool DeleteOrder(void);
};
//+------------------------------------------------------------------+
//| Constructor |
//+------------------------------------------------------------------+
CEngine::CEngine(): m_expiration(TimeCurrent()),
m_expirationorders(false),
m_trade(NULL),
m_deviation(10),
m_flag_error_params(false),
m_status_pos(false),
m_status_order(false),
m_status_expiration(false),
m_status_trading_hours(false),
m_shift_points_order(0),
m_ticket_buy(-1),
m_ticket_sell(-1),
m_last_ticket(-1),
m_num_orders_buy(0),
m_num_orders_sell(0)
{
m_adjusted_point = 10;
m_period = WRONG_VALUE;
m_typefilling = ORDER_FILLING_RETURN;
}
//+------------------------------------------------------------------+
//| Destructor |
//+------------------------------------------------------------------+
CEngine::~CEngine()
{
}
//+------------------------------------------------------------------+
//| Init |
//+------------------------------------------------------------------+
bool CEngine::Init(string expert_name,string symbol,ENUM_TIMEFRAMES period,bool every_tick,ulong magic=0,double lot=0.000000)
{
//---
if(period==PERIOD_CURRENT)
period=::Period();
//--- initialize common information
if(m_symbol==NULL)
{
if((m_symbol=new CSymbolInfo)==NULL)
return(false);
}
if(!m_symbol.Name(symbol))
return(false);
//---
m_expertname=expert_name;
m_period=period;
m_magic=magic;
m_every_tick=every_tick;
m_lote=(lot==0)?m_symbol.LotsMin():lot;
SetMarginMode();
MaxOrders(1);
//--- tuning for 3 or 5 digits
double digits_adjust=(m_symbol.Digits()==1 ||m_symbol.Digits()==3 || m_symbol.Digits()==5) ? 1/_Point : 1;
m_adjusted_point=m_symbol.Point()*digits_adjust;
//--- initializing objects expert
if(!InitTrade(magic))
{
printf(ERROR_SUFFIX+"error initialization trade object");
return(false);
}
//--- primary initialization is successful, pass to the phase of tuning
m_init_phase=INIT_PHASE_TUNING;
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Init Trade |
//+------------------------------------------------------------------+
bool CEngine::InitTrade(ulong magic,CTrade *trade=NULL)
{
//--- delete an existing object
if(m_trade!=NULL)
delete m_trade;
//--
if(trade==NULL)
{
if((m_trade=new CTrade)==NULL)
return(false);
}
else
m_trade=trade;
//--- tune trade object
m_trade.SetExpertMagicNumber(magic);
m_trade.SetMarginMode();
m_trade.SetTypeFilling(m_typefilling);
//--- set max deviation in points
m_trade.SetDeviationInPoints((ulong)(3*m_deviation*m_adjusted_point));
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Init money |
//+------------------------------------------------------------------+
bool CEngine::InitMoney(CExpertMoney *money)
{
if(m_money!=NULL)
delete m_money;
//---
if(money==NULL)
{
if((m_money=new CExpertMoney)==NULL)
return(false);
}
else
m_money=money;
//--- initializing trailing object
if(!m_money.Init(m_symbol.Name(),m_magic))
return(false);
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Init Strategy |
//+------------------------------------------------------------------+
bool CEngine::InitStrategy(CExpertStrategy *strategy)
{
if(m_strategy!=NULL)
delete m_strategy;
//--- no stop loss
if(strategy==NULL)
{
if((m_strategy=new CExpertStrategy)==NULL)
return(false);
}
else
m_strategy=strategy;
//--- initializing stop loss object
if(!m_strategy.Init(GetPointer(m_symbol),m_period,m_adjusted_point,m_magic,m_other_ticker,m_type_operation,m_direction))
return(false);
m_strategy.EveryTick(m_every_tick);
m_strategy.Magic(m_magic);
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Init Stop Loss |
//+------------------------------------------------------------------+
bool CEngine::InitStopLoss(CExpertStopLoss *stoploss)
{
if(m_stoploss!=NULL)
delete m_stoploss;
//--- no stop loss
if(stoploss==NULL)
{
if((m_stoploss=new CExpertStopLoss)==NULL)
return(false);
}
else
m_stoploss=stoploss;
//--- initializing stop loss object
if(!m_stoploss.Init(GetPointer(m_symbol),m_period,m_adjusted_point,m_magic,m_other_ticker,m_type_operation,m_direction))
return(false);
m_stoploss.EveryTick(m_every_tick);
m_stoploss.Magic(m_magic);
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Init Take Profit |
//+------------------------------------------------------------------+
bool CEngine::InitTakeProfit(CExpertTakeProfit *takeprofit)
{
if(m_takeprofit!=NULL)
delete m_takeprofit;
//--- no take profit
if(takeprofit==NULL)
{
if((m_takeprofit=new CExpertTakeProfit)==NULL)
return(false);
}
else
m_takeprofit=takeprofit;
//--- initializing take profit object
if(!m_takeprofit.Init(GetPointer(m_symbol),m_period,m_adjusted_point,m_magic,m_other_ticker,m_type_operation,m_direction))
return(false);
m_takeprofit.EveryTick(m_every_tick);
m_takeprofit.Magic(m_magic);
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Validation settings |
//+------------------------------------------------------------------+
bool CEngine::ValidationSettings(void)
{
if(!CEngineBase::ValidationSettings())
return(false);
//--- Check strategy parameters
if(!m_money.ValidationSettings())
{
printf(ERROR_SUFFIX+"error money parameters.");
return(false);
}
//--- Check strategy parameters
if(!m_strategy.ValidationSettings())
{
printf(ERROR_SUFFIX+"error strategy parameters.");
return(false);
}
//--- Check stop loss parameters
if(!m_stoploss.ValidationSettings())
{
printf(ERROR_SUFFIX+"error stop loss parameters.");
return(false);
}
//--- Check take profit parameters
if(!m_takeprofit.ValidationSettings())
{
printf(ERROR_SUFFIX+"error take profit parameters.");
return(false);
}
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Initialization filters |
//+------------------------------------------------------------------+
bool CEngine::InitFilters(CExpertFilter *_filters)
{
//--- create required filters
if(!CEngineBase::InitFilters(_filters))
{
printf(ERROR_SUFFIX+"error initialization filters of strategy.");
return(false);
}
//---
return(true);
}
//+------------------------------------------------------------------+
//| Init Linear Regression Filter |
//+------------------------------------------------------------------+
bool CEngine::InitLinearRegressionFilter(bool is_usage,
string symbol,
ENUM_TIMEFRAMES LinearRegressionFilter_TF,
int PeriodoLinearRegressionFilter_,
ENUM_FILTER_LINEAR_REGRESSION_DIRECTION LinearRegressionDirection_,
bool LinearRegressionFilterUseLocation_,
ENUM_FILTER_LINEAR_REGRESSION_LOCATION LinearRegressionLocation_Buy_,
ENUM_FILTER_LINEAR_REGRESSION_LOCATION LinearRegressionLocation_Sell_)
{
m_LRFilter_Is_Usage=is_usage;
//--- check if is usage
if(is_usage)
{
//--- init LR Buy
m_LRFilter_Buy=new CLinearRegressionFilter;
if(!m_LRFilter_Buy.Init(symbol,
LinearRegressionFilter_TF,
false,
PeriodoLinearRegressionFilter_,
LinearRegressionDirection_,
LinearRegressionFilterUseLocation_,
LinearRegressionLocation_Buy_))
{
return(false);
}
//--- check pointer
if(!CheckPointer(m_LRFilter_Buy))
return(false);
//--- init LR Sell
m_LRFilter_Sell=new CLinearRegressionFilter;
if(!m_LRFilter_Sell.Init(symbol,
LinearRegressionFilter_TF,
true,
PeriodoLinearRegressionFilter_,
LinearRegressionDirection_,
LinearRegressionFilterUseLocation_,
LinearRegressionLocation_Sell_))
{
return(false);
}
//--- check pointer
if(!CheckPointer(m_LRFilter_Sell))
return(false);
//--- ok
return(true);
}
else
{
//--- delete pointer if is not null
if(m_LRFilter_Buy!=NULL)
delete m_LRFilter_Buy;
m_LRFilter_Buy=NULL;
//--- delete pointer if is not null
if(m_LRFilter_Sell!=NULL)
delete m_LRFilter_Sell;
m_LRFilter_Sell=NULL;
//---
return(true);
}
}
//+------------------------------------------------------------------+
//| Initialization indicators |
//+------------------------------------------------------------------+
bool CEngine::InitIndicators(CIndicators *indicators)
{
//--- NULL always comes as the parameter, but here it's not significant for us
CIndicators *indicators_ptr=GetPointer(m_indicators);
//--- create required timeseries
if(!CEngineBase::InitIndicators(indicators_ptr))
return(false);
//---
if(!m_strategy.InitIndicators(indicators_ptr))
{
printf(ERROR_SUFFIX+"error initialization indicators of strategy object.");
return(false);
}
//---
if(!m_stoploss.InitIndicators(indicators_ptr))
{
printf(ERROR_SUFFIX+"error initialization indicators of stop loss object.");
return(false);
}
//---
if(!m_takeprofit.InitIndicators(indicators_ptr))
{
printf(ERROR_SUFFIX+"error initialization indicators of take profit object.");
return(false);
}
//--- initialization complete
printf(ALERT_SUFIX+"%s completamente carregado. Ativo operante: %s. Time Frame: %s.",m_expertname,m_symbol.Name(),EnumToString(m_period));
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Get trading hours |
//+------------------------------------------------------------------+
bool CEngine::GetHours(ENUM_TYPE_HOURS ini,ENUM_TYPE_HOURS orders,ENUM_TYPE_HOURS end)
{
//--- masks of the bits
int mask_min=63;
int mask_hour=31;
//--- hour init trades
m_minutoInicioAbertura=mask_min&int(ini);
m_horaInicioAbertura=mask_hour&int(ini)>>6;
//--- hour of end emition ordens
m_minFimOrdens=mask_min&int(orders);
m_horaFimOrdens=mask_hour&int(orders)>>6;
//--- hour of end trades
m_minutoFimAbertura=mask_min&int(end);
m_horaFimAbertura=mask_hour&int(end)>>6;
//--- if simple hour used
if(m_simple_hour_flag)
{
switch(m_simple_hour)
{
case HOUR_0905_1300:
m_horaInicioAbertura=9;
m_minutoInicioAbertura=5;
m_horaFimOrdens=13;
m_minFimOrdens=0;
m_horaFimAbertura=17;
m_minutoFimAbertura=45;
break;
case HOUR_0905_1730:
m_horaInicioAbertura=9;
m_minutoInicioAbertura=5;
m_horaFimOrdens=17;
m_minFimOrdens=30;
m_horaFimAbertura=17;
m_minutoFimAbertura=45;
break;
case HOUR_1300_1730:
m_horaInicioAbertura=13;
m_minutoInicioAbertura=0;
m_horaFimOrdens=17;
m_minFimOrdens=30;
m_horaFimAbertura=17;
m_minutoFimAbertura=45;
break;
}
}
//--- check input values
if(m_horaInicioAbertura>m_horaFimAbertura || m_horaInicioAbertura>m_horaFimOrdens)
{
printf(ERROR_SUFFIX+"error, Trading Hours Inconsistency! Check the inputs parametres.");
return(false);
}
if(m_horaInicioAbertura==m_horaFimOrdens && m_minutoInicioAbertura>=m_minFimOrdens)
{
printf(ERROR_SUFFIX+"error, Trading Hours Inconsistency! Check the inputs parametres.");
return(false);
}
if(m_horaInicioAbertura==m_horaFimAbertura && m_minutoInicioAbertura>=m_minutoFimAbertura)
{
printf(ERROR_SUFFIX+"error, Trading Hours Inconsistency! Check the inputs parametres.");
return(false);
}
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Check Trading Hours |
//+------------------------------------------------------------------+
bool CEngine::CheckTradingHours(void)
{
//--- define the variable horaAtual
MqlDateTime horaAtual;
//---
TimeToStruct(TimeCurrent(), horaAtual);
if(horaAtual.hour>=m_horaInicioAbertura && horaAtual.hour<=m_horaFimAbertura)
{
if(horaAtual.hour==m_horaInicioAbertura)
{
if(horaAtual.min>=m_minutoInicioAbertura)
return(true);
else
return(false);
}
if(horaAtual.hour==m_horaFimAbertura)
{
if(horaAtual.min<=m_minutoFimAbertura)
return(true);
else
return(false);
}
return(true);
}
else
return(false);
}
//+------------------------------------------------------------------+
//| Checking closing time |
//+------------------------------------------------------------------+
bool CEngine::IsClosingTime()
{
MqlDateTime hora_atual;
TimeToStruct(TimeCurrent(), hora_atual);
if(hora_atual.hour>m_horaFimAbertura)
return(true);
if((hora_atual.hour==m_horaFimAbertura) && (hora_atual.min>=m_minutoFimAbertura))
return(true);
return(false);
}
//+------------------------------------------------------------------+
//| Checking close market |
//+------------------------------------------------------------------+
bool CEngine::IsCloseMarket()
{
MqlDateTime hora_atual;
TimeToStruct(TimeCurrent(), hora_atual);
if(hora_atual.hour<m_horaInicioAbertura)
return(true);
if((hora_atual.hour==m_horaInicioAbertura) && (hora_atual.min<=m_minutoInicioAbertura))
return(true);
return(false);
}
//+------------------------------------------------------------------+
//| Check expiration orders |
//+------------------------------------------------------------------+
bool CEngine::CheckExpirationOrders(void)
{
//--- define the variable horaAtual
MqlDateTime horaAtual;
//---
TimeToStruct(TimeCurrent(), horaAtual);
if(horaAtual.hour>=m_horaInicioAbertura && horaAtual.hour<=m_horaFimOrdens)
{
if(horaAtual.hour==m_horaInicioAbertura)
{
if(horaAtual.min>=m_minutoInicioAbertura)
return(true);
else
return(false);
}
if(horaAtual.hour==m_horaFimOrdens)
{
if(horaAtual.min<=m_minFimOrdens)
return(true);
else
return(false);
}
return(true);
}
else
return(false);
}
//+------------------------------------------------------------------+
//| Manange Trade |
//+------------------------------------------------------------------+
bool CEngine::CloseTrade(void)
{
//---
m_close_trade=false;
//---
MqlDateTime dts_init,dts_end;
switch(m_trade_closing)
{
//--- closing three days
case TRADE_CLOSING_3DIAS:
TimeToStruct(m_init_swing,dts_init);
TimeToStruct(TimeCurrent(),dts_end);
if(dts_init.day_of_week==MONDAY && (dts_end.day_of_week==THURSDAY || dts_end.day_of_week==FRIDAY)) //closes the following day in case of public holidays
m_close_trade=true;
if(dts_init.day_of_week==TUESDAY && (dts_end.day_of_week==FRIDAY || dts_end.day_of_week==MONDAY)) //closes the following day in case of public holidays
m_close_trade=true;
if(dts_init.day_of_week==WEDNESDAY && (dts_end.day_of_week==MONDAY || dts_end.day_of_week==TUESDAY)) //closes the following day in case of public holidays
m_close_trade=true;
if(dts_init.day_of_week==THURSDAY && (dts_end.day_of_week==TUESDAY || dts_end.day_of_week==WEDNESDAY)) //closes the following day in case of public holidays
m_close_trade=true;
if(dts_init.day_of_week==FRIDAY && (dts_end.day_of_week==WEDNESDAY || dts_end.day_of_week==THURSDAY)) //closes the following day in case of public holidays
m_close_trade=true;
break;
//--- closing five days
case TRADE_CLOSING_5DIAS:
TimeToStruct(m_init_swing,dts_init);
TimeToStruct(TimeCurrent(),dts_end);
if(dts_init.day_of_week==dts_end.day_of_week)
{
if(dts_end.day>dts_init.day)
m_close_trade=true;
if(dts_end.mon!=dts_init.mon)
m_close_trade=true;
}
break;
//--- closeing in friday
case TRADE_CLOSING_SEXTA:
TimeToStruct(TimeCurrent(),dts_end);
if(dts_end.day_of_week==FRIDAY)
m_close_trade=true;
break;
//--- closeing daily
case TRADE_CLOSING_DIARIO:
m_close_trade=true;
break;
//--- not closing
default:
m_close_trade=false;
break;
}
return(m_close_trade);
}
//+------------------------------------------------------------------+
//| Deinitialization expert |
//+------------------------------------------------------------------+
void CEngine::Deinit(void)
{
//--- delete trade class
DeinitTrade();
//--- delete money class
DeinitMoney();
//--- delete strategy class
DeinitStrategy();
//--- delete stop loss class
DeinitStopLoss();
//--- delete take profit class
DeinitTakeProfit();
//--- delete indicators collection
DeinitIndicators();
//--- deinit base
CEngineBase::DeInit();
}
//+------------------------------------------------------------------+
//| Deinitialization trade object |
//+------------------------------------------------------------------+
void CEngine::DeinitTrade(void)
{
if(m_trade!=NULL)
{
delete m_trade;
m_trade=NULL;
}
}
//+------------------------------------------------------------------+
//| Deinitialization money object |
//+------------------------------------------------------------------+
void CEngine::DeinitMoney(void)
{
if(m_money!=NULL)
{
delete m_money;
m_money=NULL;
}
}
//+------------------------------------------------------------------+
//| Deinitialization strategy object |
//+------------------------------------------------------------------+
void CEngine::DeinitStrategy(void)
{
if(m_strategy!=NULL)
{
delete m_strategy;
m_strategy=NULL;
}
}
//+------------------------------------------------------------------+
//| Deinitialization stop loss object |
//+------------------------------------------------------------------+
void CEngine::DeinitStopLoss(void)
{
if(m_stoploss!=NULL)
{
delete m_stoploss;
m_stoploss=NULL;
}
}
//+------------------------------------------------------------------+
//| Deinitialization take profit object |
//+------------------------------------------------------------------+
void CEngine::DeinitTakeProfit(void)
{
if(m_takeprofit!=NULL)
{
delete m_takeprofit;
m_takeprofit=NULL;
}
}
//+------------------------------------------------------------------+
//| Deinitialization indicators |
//+------------------------------------------------------------------+
void CEngine::DeinitIndicators(void)
{
//--- clear indicators
m_indicators.Clear();
}
//+------------------------------------------------------------------+
//| OnTick handler |
//+------------------------------------------------------------------+
void CEngine::OnTick(void)
{
//--- updated quotes and indicators
if(!Refresh())
return;
//--- OnTick metric process
//--- update status
m_status_expiration=CheckExpirationOrders();
m_status_trading_hours=CheckTradingHours();
m_status_pos=SelectPosition();
m_status_order=SelectOrder();
//--- expert processing
Processing();
}
//+------------------------------------------------------------------+
//| Refreshing data for processing |
//+------------------------------------------------------------------+
bool CEngine::Refresh(void)
{
//--- refresh rates
if(!m_symbol.RefreshRates())
return(false);
//--- refresh indicators
m_indicators.Refresh();
//--- refresh filters
m_filters.Refresh();
//--- ok
return(true);
}
//+------------------------------------------------------------------+
//| Select position |
//+------------------------------------------------------------------+
bool CEngine::SelectPosition(void)
{
bool res=false;
//---
if(PositionSelectByTicket(m_last_ticket))
res|=m_position.SelectByTicket(m_last_ticket);
//---
return(res);
}
//+------------------------------------------------------------------+
//| Select orders |
//+------------------------------------------------------------------+
bool CEngine::SelectOrder(void)
{
//---
bool res=false;
if(OrderSelect(m_ticket_buy))
res|=m_order.Select(m_ticket_buy);
if(OrderSelect(m_ticket_sell))
res|=m_order.Select(m_ticket_sell);
//---
return(res);
}
//+------------------------------------------------------------------+
//| Main Method (Processing) |
//+------------------------------------------------------------------+
bool CEngine::Processing(void)
{
//--- init checking
if(!InitChecking())
return(false);
//--- if position open
if(m_status_pos)
{
//---
if(IsEntryOut(m_flag_tick))
{
//--- check stop loss
if(CheckStopLoss())
return(true);
//--- check take profit
if(CheckTakeProfit())
return(true);
}
}
//--- no position open
if(IsEntryIn(m_flag_tick_in))
{
//--- check order send
if(!m_status_pos)
{
//--- if pending order
if(m_status_order && m_status_expiration)
if(CheckTrailingOrder())
return(true);
//--- check expiration pending orders
if(m_status_expiration)
{
//--- check all filters
if(!m_filters[1])
return(false);
//--- check the possibility of opening a position/setting pending order
if(CheckOpen())
return(true);
}
}
}
//---
return(false);
}
//+------------------------------------------------------------------+
//| Init Checking |
//+------------------------------------------------------------------+
bool CEngine::InitChecking(void)
{
//--- check the expiration orders
if(!m_status_expiration)
{
if(m_status_order)
{
if(ExpirationOrders())
{
DeleteOrders();
printf(ALERT_SUFIX+"Ordens pendentes removidas - Término do envio de ordens pendentes.");
return(false);
}
}
}
//--- check the trading hours
if(IsClosingTime())
{
if(CloseTrade())
{
if(m_status_pos)
{
Close();
printf(ALERT_SUFIX+"Posição de Ticket= %I64d foi fechada - Encerramento do Trade.",m_position.Ticket());
}
if(m_status_order)
{
DeleteOrders();
printf(ALERT_SUFIX+"Ordens pendentes removidas - Encerramento do Trade.");
}
return(false);
}
return(true);
}
return(true);
}
//+------------------------------------------------------------------+
//| Check for position open or limit/stop order set |
//+------------------------------------------------------------------+
bool CEngine::CheckOpen(void)
{
//--- check possibility of open long
CheckOpenLong();
//--- check possibility of open short
CheckOpenShort();
//--- return without operations
return(true);
}
//+------------------------------------------------------------------+
//| Check for long position open or limit/stop order set |
//+------------------------------------------------------------------+
bool CEngine::CheckOpenLong(void)
{
double price=EMPTY_VALUE;
double sl=0.0;
double tp=0.0;
datetime expiration=TimeCurrent();
//--- check type operation
if(GetTypeOperation()==TYPE_SELL_ONLY)
return(false);
//--- check max pending orders
if(MaxOrders()<=NumPendingOrdersBuy())
return(false);
//--- check linear regression filter
if(m_LRFilter_Is_Usage)
if(!m_LRFilter_Buy[1])
return(false);
//--- check the signal for long enter operations
if(m_strategy.CheckOpenLong(price,sl,tp,expiration))
{
//--- check shift points
double shift=ShiftOrderPoints();
//--- normalize price
price=m_symbol.NormalizePrice(price+shift);
//--- check stop loss
if(m_stoploss.CheckStopLossLong(price,sl,tp))
{
if((sl==-2 && tp==-2) || price==sl)
return(false);
}
else
return(false); //--- is proibited empty stop loss
sl=sl==0.0?sl:m_symbol.NormalizePrice(sl+shift);
//--- check take profit
if(m_takeprofit.CheckTakeProfitLong(price,sl,tp))
{
if((sl==-2 && tp==-2) || price==tp)
return(false);
}
tp=tp==0.0?tp:m_symbol.NormalizePrice(tp+shift);
//--- set expiration order
//--- create request
ZeroRequest();
//---
m_request.magic = m_magic;
m_request.symbol = m_symbol.Name();
//--- update lot
m_lote =m_money.Lot(price,sl);
//---
m_request.volume = m_lote;
m_request.price = price;
m_request.sl = sl;
m_request.tp = tp;
//--- set request type
m_request.action =TRADE_ACTION_DEAL;
m_request.type =ORDER_TYPE_BUY;
//---
m_request.type_filling = m_typefilling;
m_request.type_time = ORDER_TIME_DAY;
m_request.comment = "Order Buy";
//--- order check
if(!OrderCheck(m_request,m_check_result))
{
ResetLastError();
printf(ALERT_SUFIX+"ORDEM INVÁLIDA - Retcode: %d (Magic = %I64d Lot = %.2f Price = %.2f SL = %.2f TP = %.2f)",m_check_result.retcode,m_magic,m_lote,price,sl,tp);
return(false);
}
//--- uptade ticket order buy
if(OrderSend(m_request,m_result))
{
m_ticket_buy=m_result.order;
if(m_result.retcode==10009)
{
printf(ALERT_SUFIX+"Ordem de compra enviada com sucesso - Retcode: %d \n(Magic = %I64d Lot = %.2f Price = %.2f SL = %.2f TP = %.2f)",m_result.retcode,m_magic,m_lote,price,sl,tp);
return(true);
}
else
{
printf(ALERT_SUFIX+"ORDEM INVÁLIDA - Retcode: %d (Magic = %I64d Lot = %.2f Price = %.2f SL = %.2f TP = %.2f)",m_result.retcode,m_magic,m_lote,price,sl,tp);
return(false);
}
}
else
{
printf(ALERT_SUFIX+"ORDEM NÃO ENVIADA - Retcode: %d (Magic = %I64d Lot = %.2f Price = %.2f SL = %.2f TP = %.2f)",m_result.retcode,m_magic,m_lote,price,sl,tp);
//--- failure in open long position param
return(false);
}
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Check for short position open or limit/stop order set |
//+------------------------------------------------------------------+
bool CEngine::CheckOpenShort(void)
{
double price=EMPTY_VALUE;
double sl=0.0;
double tp=0.0;
datetime expiration=TimeCurrent();
//--- check type operation
if(GetTypeOperation()==TYPE_BUY_ONLY)
return(false);
//--- check max pending orders
if(MaxOrders()<=NumPendingOrdersSell())
return(false);
//--- check linear regression filter
if(m_LRFilter_Is_Usage)
if(!m_LRFilter_Sell[1])
return(false);
//--- check de signal for short enter operations
if(m_strategy.CheckOpenShort(price,sl,tp,expiration))
{
//--- check shift points
double shift=ShiftOrderPoints();
//--- normalize price
price=m_symbol.NormalizePrice(price-shift);
//--- check stop loss
if(m_stoploss.CheckStopLossShort(price,sl,tp))
{
if((sl==-2 && tp==-2) || price==sl)
return(false);
}
sl=sl==0.0?sl:m_symbol.NormalizePrice(sl-shift);
//--- check take profit
if(m_takeprofit.CheckTakeProfitShort(price,sl,tp))
{
if((sl==-2 && tp==-2) || price==tp)
return(false);
}
tp=tp==0.0?tp:m_symbol.NormalizePrice(tp-shift);
//--- set expiration order
//--- create request
ZeroRequest();
//---
m_request.magic = m_magic;
m_request.symbol = m_symbol.Name();
//--- update lot
m_lote =m_money.Lot(price,sl);
//---
m_request.volume = m_lote;
m_request.price = price;
m_request.sl = sl;
m_request.tp = tp;
//--- set request type
m_request.action =TRADE_ACTION_DEAL;
m_request.type =ORDER_TYPE_SELL;
//---
m_request.type_filling = m_typefilling;
m_request.type_time = ORDER_TIME_DAY;
m_request.comment = "Order Sell";
//--- order check
if(!OrderCheck(m_request,m_check_result))
{
ResetLastError();
printf(ALERT_SUFIX+"ORDEM INVÁLIDA - Retcode: %d (Magic = %I64d Lot = %.2f Price = %.2f SL = %.2f TP = %.2f)",m_check_result.retcode,m_magic,m_lote,price,sl,tp);
return(false);
}
//--- uptade ticket order sell
if(OrderSend(m_request,m_result))
{
m_ticket_sell=m_result.order;
if(m_result.retcode==10009)
{
printf(ALERT_SUFIX+"Ordem de venda enviada com sucesso - Retcode: %d \n(Magic = %I64d Lot = %.2f Price = %.2f SL = %.2f TP = %.2f)",m_result.retcode,m_magic,m_lote,price,sl,tp);
return(true);
}
else
{
printf(ALERT_SUFIX+"ORDEM INVÁLIDA - Retcode: %d (Magic = %I64d Lot = %.2f Price = %.2f SL = %.2f TP = %.2f)",m_result.retcode,m_magic,m_lote,price,sl,tp);
return(false);
}
}
else
{
printf(ALERT_SUFIX+"ORDEM NÃO ENVIADA - Retcode: %d (Magic = %I64d Lot = %.2f Price = %.2f SL = %.2f TP = %.2f)",m_result.retcode,m_magic,m_lote,price,sl,tp);
//--- failure in open long position param
return(false);
}
}
//--- failure
return(false);
}
//+------------------------------------------------------------------+
//| Zero Request |
//+------------------------------------------------------------------+
void CEngine::ZeroRequest(void)
{
//--- zero memory
ZeroMemory(m_request);
ZeroMemory(m_result);
ZeroMemory(m_check_result);
}
//+------------------------------------------------------------------+
//| Check for stop loss position |
//+------------------------------------------------------------------+
bool CEngine::CheckStopLoss(void)
{
//--- position must be selected before call
if(m_position.PositionType()==POSITION_TYPE_BUY)
{
//--- check the possibility of modifying the long position
if(CheckStopLossLong())
return(true);
}
else
{
//--- check the possibility of modifying the short position
if(CheckStopLossShort())
return(true);
}
//--- return without operations
return(false);
}
//+------------------------------------------------------------------+
//| Check for take profit long position |
//+------------------------------------------------------------------+
bool CEngine::CheckStopLossLong(void)
{
double sl=EMPTY_VALUE;
double tp=EMPTY_VALUE;
//--- check for long stop loss operations
if(m_stoploss.CheckStopLossLong(GetPointer(m_position),sl,tp))
{
double position_sl=m_position.StopLoss();
double position_tp=m_position.TakeProfit();
if(sl==EMPTY_VALUE)
sl=position_sl;
else
sl=(sl<0)?sl:m_symbol.NormalizePrice(sl);
if(tp==EMPTY_VALUE)
tp=position_tp;
else
tp=(tp<0)?tp:m_symbol.NormalizePrice(tp);
if(sl==position_sl && tp==position_tp)
return(false);
//--- long stop loss operations
return(StopLoss(sl,tp));
}
//--- return without operations
return(false);
}
//+------------------------------------------------------------------+
//| Check for stop loss short position |
//+------------------------------------------------------------------+
bool CEngine::CheckStopLossShort(void)
{
double sl=EMPTY_VALUE;
double tp=EMPTY_VALUE;
//--- check for short stop loss operations
if(m_stoploss.CheckStopLossShort(GetPointer(m_position),sl,tp))
{
double position_sl=m_position.StopLoss();
double position_tp=m_position.TakeProfit();
if(sl==EMPTY_VALUE)
sl=position_sl;
else
sl=(sl<0)?sl:m_symbol.NormalizePrice(sl);
if(tp==EMPTY_VALUE)
tp=position_tp;
else
tp=(tp<0)?tp:m_symbol.NormalizePrice(tp);
if(sl==position_sl && tp==position_tp)
return(false);
//--- short stop loss operations
return(StopLoss(sl,tp));
}
//--- return without operations
return(false);
}
//+------------------------------------------------------------------+
//| Stop Loss long position |
//+------------------------------------------------------------------+
bool CEngine::StopLoss(double sl,double tp)
{
if(sl<0)
return(m_trade.PositionClose(m_position.Ticket()));
else
return(m_trade.PositionModify(m_position.Ticket(),sl,tp));
}
//+------------------------------------------------------------------+
//| Check for take profit position |
//+------------------------------------------------------------------+
bool CEngine::CheckTakeProfit(void)
{
//--- position must be selected before call
if(m_position.PositionType()==POSITION_TYPE_BUY)
{
//--- check the possibility of modifying the long position
if(CheckTakeProfitLong())
return(true);
}
else
{
//--- check the possibility of modifying the short position
if(CheckTakeProfitShort())
return(true);
}
//--- return without operations
return(false);
}
//+------------------------------------------------------------------+
//| Check for take profit long position |
//+------------------------------------------------------------------+
bool CEngine::CheckTakeProfitLong(void)
{
double sl=EMPTY_VALUE;
double tp=EMPTY_VALUE;
//--- check for long take profit operations
if(m_takeprofit.CheckTakeProfitLong(GetPointer(m_position),sl,tp))
{
double position_sl=m_position.StopLoss();
double position_tp=m_position.TakeProfit();
if(sl==EMPTY_VALUE)
sl=position_sl;
else
sl=(sl<0)?sl:m_symbol.NormalizePrice(sl);
if(tp==EMPTY_VALUE)
tp=position_tp;
else
tp=(tp<0)?tp:m_symbol.NormalizePrice(tp);
if(sl==position_sl && tp==position_tp)
return(false);
//--- long step stop operations
return(TakeProfit(sl,tp));
}
//--- return without operations
return(false);
}
//+------------------------------------------------------------------+
//| Check for take profit short position |
//+------------------------------------------------------------------+
bool CEngine::CheckTakeProfitShort(void)
{
double sl=EMPTY_VALUE;
double tp=EMPTY_VALUE;
//--- check for short take profit operations
if(m_takeprofit.CheckTakeProfitShort(GetPointer(m_position),sl,tp))
{
double position_sl=m_position.StopLoss();
double position_tp=m_position.TakeProfit();
if(sl==EMPTY_VALUE)
sl=position_sl;
else
sl=(sl<0)?sl:m_symbol.NormalizePrice(sl);
if(tp==EMPTY_VALUE)
tp=position_tp;
else
tp=(tp<0)?tp:m_symbol.NormalizePrice(tp);
if(sl==position_sl && tp==position_tp)
return(false);
//--- short take profitp operations
return(TakeProfit(sl,tp));
}
//--- return without operations
return(false);
}
//+------------------------------------------------------------------+
//| Take Profit long position |
//+------------------------------------------------------------------+
bool CEngine::TakeProfit(double sl,double tp)
{
if(tp<0)
return(m_trade.PositionClose(m_position.Ticket()));
else
return(m_trade.PositionModify(m_position.Ticket(),sl,tp));
}
//+------------------------------------------------------------------+
//| Close position open |
//+------------------------------------------------------------------+
bool CEngine::Close(void)
{
//---
bool res=true;
ResetLastError();
//--- close all postitions
int total=PositionsTotal();
for(int i=0; i<total; i++)
{
if(m_position.SelectByIndex(i))
{
ulong ticket=m_position.Ticket();
res&=m_trade.PositionClose(ticket);
}
}
//--- ok
return(res);
}
//+------------------------------------------------------------------+
//| Close position open by ticket |
//+------------------------------------------------------------------+
bool CEngine::CloseByTicket(ulong ticket)
{
return(m_trade.PositionClose(ticket));
}
//+------------------------------------------------------------------+
//| Delete all limit/stop orders |
//+------------------------------------------------------------------+
bool CEngine::DeleteOrders(void)
{
bool res=true;
ResetLastError();
//--- delete all pending orders
int total=OrdersTotal();
for(int i=0; i<total; i++)
{
if(m_order.SelectByIndex(i))
{
//--- clear structs
ZeroRequest();
//--- setting request
m_request.action =TRADE_ACTION_REMOVE;
m_request.magic =m_magic;
m_request.order =m_order.Ticket();
//--- action and return the result
res&=OrderSend(m_request,m_result);
}
}
//---
return(res);
}
//+------------------------------------------------------------------+
//| Delete limit/stop order |
//+------------------------------------------------------------------+
bool CEngine::DeleteOrder(void)
{
return(m_trade.OrderDelete(m_order.Ticket()));
}
//+------------------------------------------------------------------+
//| OnTradeTransaction Handler |
//+------------------------------------------------------------------+
void CEngine::OnTradeTransaction(const MqlTradeTransaction &trans,const MqlTradeRequest &request,const MqlTradeResult &result)
{
//---
switch(trans.type)
{
//--- working with adding orders
case TRADE_TRANSACTION_ORDER_ADD:
//--- order buy add
if((trans.order_type==ORDER_TYPE_BUY_LIMIT || trans.order_type==ORDER_TYPE_BUY_STOP) && (m_ticket_buy==trans.order))
{
m_num_orders_buy++;
}
//--- order sell add
if((trans.order_type==ORDER_TYPE_SELL_LIMIT || trans.order_type==ORDER_TYPE_SELL_STOP) && (m_ticket_sell==trans.order))
{
m_num_orders_sell++;
}
break;
//--- working with canceled orders
case TRADE_TRANSACTION_ORDER_DELETE:
if(trans.order==trans.position)
{
//--- from pending order to position buy open
if((trans.order_type==ORDER_TYPE_BUY_LIMIT || trans.order_type==ORDER_TYPE_BUY_STOP) && (m_ticket_buy==trans.order))
{
m_last_ticket=trans.position;
m_num_orders_buy--;
}
//--- from pending order to position sell open
if((trans.order_type==ORDER_TYPE_SELL_LIMIT || trans.order_type==ORDER_TYPE_SELL_STOP) && (m_ticket_sell==trans.order))
{
m_last_ticket=trans.position;
m_num_orders_sell--;
}
}
else
{
//--- pending order to buy canceled
if((trans.order_type==ORDER_TYPE_BUY_LIMIT || trans.order_type==ORDER_TYPE_BUY_STOP) && (m_ticket_buy==trans.order))
{
//--- order that was deleted (not necessarily pending order)
m_num_orders_buy--;
}
else
if((trans.order_type==ORDER_TYPE_SELL_LIMIT || trans.order_type==ORDER_TYPE_SELL_STOP) && (m_ticket_sell==trans.order))
{
m_num_orders_sell--;
}
}
break;
//--- working with canceled orders
case TRADE_TRANSACTION_DEAL_ADD:
{
switch(trans.deal_type)
{
//--- buy
case DEAL_TYPE_BUY:
if(m_ticket_buy==trans.order)
{
//--- update ticket of new position
m_last_ticket=trans.order;
}
break;
//--- sell
case DEAL_TYPE_SELL:
if(m_ticket_sell==trans.order)
{
//--- update ticket of new position
m_last_ticket=trans.order;
}
break;
}
}
break;
}
}
//+------------------------------------------------------------------+
//| Verify is New Bar by Flag |
//+------------------------------------------------------------------+
bool CEngine::IsEntryIn(bool flag)
{
//--- if false, evaluate the outputs every minute
ENUM_TIMEFRAMES period=m_period;
if(flag)
period=PERIOD_M1;
//--- memorize the time of opening of the last bar in the static variable
static datetime last_time=0;
//--- current time
datetime lastbar_time=(datetime)SeriesInfoInteger(m_symbol.Name(),period,SERIES_LASTBAR_DATE);
//--- if it is the first call of the function
if(last_time==0)
{
//--- set the time and exit
last_time=lastbar_time;
return(true);
}
//--- if the time differs
if(last_time!=lastbar_time)
{
//--- memorize the time and return true
last_time=lastbar_time;
return(true);
}
//--- if we passed to this line, then the bar is not new; return false
return(false);
}
//+------------------------------------------------------------------+
//| Verify is New Bar by Flag |
//+------------------------------------------------------------------+
bool CEngine::IsEntryOut(bool flag)
{
//--- if false, evaluate the outputs every minute
ENUM_TIMEFRAMES period=m_period;
if(flag)
period=PERIOD_M1;
//--- memorize the time of opening of the last bar in the static variable
static datetime last_time=0;
//--- current time
datetime lastbar_time=(datetime)SeriesInfoInteger(m_symbol.Name(),period,SERIES_LASTBAR_DATE);
//--- if it is the first call of the function
if(last_time==0)
{
//--- set the time and exit
last_time=lastbar_time;
return(true);
}
//--- if the time differs
if(last_time!=lastbar_time)
{
//--- memorize the time and return true
last_time=lastbar_time;
return(true);
}
//--- if we passed to this line, then the bar is not new; return false
return(false);
}
//+------------------------------------------------------------------+
//| On Tester Function |
//+------------------------------------------------------------------+
double CEngine::OnTester(void)
{
//---
double custom_metric=TesterStatistics(STAT_RECOVERY_FACTOR);
//---
return(custom_metric);
}
//+------------------------------------------------------------------+