//+------------------------------------------------------------------+ //| Two Symbols iRSI EA Class.mqh | //| Copyright © 2020, Vladimir Karputov | //| https://www.mql5.com/ru/market/product/43516 | //+------------------------------------------------------------------+ #property copyright "Copyright © 2020, Vladimir Karputov" #property link "https://www.mql5.com/ru/market/product/43516" #property version "3.116" //--- #include #include #include #include #include #include #include "TradingEngineEnums.mqh" //+------------------------------------------------------------------+ //| Class CTradingEngine31 | //| Appointment: Class Expert Advisor. | //| Derives from class CObject. | //+------------------------------------------------------------------+ class CTradingEngine31 : public CObject { protected: //--- CPositionInfo m_position; // object of CPositionInfo class CTrade m_trade; // object of CTrade class CSymbolInfo m_symbol; // object of CSymbolInfo class CAccountInfo m_account; // object of CAccountInfo class CDealInfo m_deal; // object of CDealInfo class CMoneyFixedMargin *m_money; // object of CMoneyFixedMargin class //--- double m_stop_loss; // Stop Loss -> double double m_take_profit; // Take Profit -> double ushort m_trailing_frequency; // Trailing, in seconds ushort m_signals_frequency; // Search signals, in seconds double m_trailing_stop; // Trailing Stop -> double double m_trailing_step; // Trailing Step -> double ENUM_LOT_OR_RISK m_lot_or_risk; // Money management: Lot OR Risk double m_volume_lot_or_risk; // The value for "Money management" ENUM_TRADE_MODE m_trade_mode; // Trade mode: ulong m_deviation; // Deviation //--- //--- bool m_only_one; // Only one positions bool m_reverse; // Reverse bool m_close_opposite; // Close opposite bool m_print_log; // Print log ulong m_magic; // Magic number uchar m_max_positions; // Maximum positions //--- int handle_iRSI; // variable for storing the handle of the iRSI indicator double m_adjusted_point; // point value adjusted for 3 or 5 points bool m_need_close_all; // close all positions datetime m_last_trailing; // "0" -> D'1970.01.01 00:00'; datetime m_last_signal; // "0" -> D'1970.01.01 00:00'; datetime m_prev_bars; // "0" -> D'1970.01.01 00:00'; datetime m_last_deal_in; // "0" -> D'1970.01.01 00:00'; int m_bar_current; //--- STRUCT_POSITION SPosition[]; private: public: CTradingEngine31(); ~CTradingEngine31(); //--- Expert initialization function int OnInit( ushort InpStopLoss, // Stop Loss, in pips (1.00045-1.00055=1 pips) ushort InpTakeProfit, // Take Profit, in pips (1.00045-1.00055=1 pips) ushort InpTrailingFrequency, // Trailing, in seconds (< "10" -> only on a new bar) ushort InpSignalsFrequency, // Search signals, in seconds (< "10" -> only on a new bar) ushort InpTrailingStop, // Trailing Stop (min distance from price to Stop Loss, in pips ushort InpTrailingStep, // Trailing Step, in pips (1.00045-1.00055=1 pips) ENUM_LOT_OR_RISK InpLotOrRisk, // Money management: Lot OR Risk double InpVolumeLotOrRisk, // The value for "Money management" ENUM_TRADE_MODE InpTradeMode, // Trade mode: string Inp_RSI_symbol, // RSI symbol int Inp_RSI_ma_period, // RSI averaging period ENUM_APPLIED_PRICE Inp_RSI_applied_price, // RSI type of price uchar InpMaxPositions, // Maximum positions ulong InpDeviation, // Deviation, in points (1.00045-1.00055=10 points) bool InpOnlyOne, // Only one positions bool InpReverse, // Reverse bool InpCloseOpposite, // Close opposite bool InpPrintLog, // Print log ulong InpMagic // Magic number ); //--- Expert deinitialization function void OnDeinit(const int reason); //--- Expert tick function void OnTick(); //--- TradeTransaction function void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result); //--- Profit all positions double ProfitAllPositions(void); //--- Close all positions void CloseAllPositions(const bool value) { m_need_close_all=value; } protected: //--- Refreshes the symbol quotes data bool RefreshRates(void); //--- Check the correctness of the position volume bool CheckVolumeValue(double volume,string &error_description); //--- Lot Check double LotCheck(double lots,CSymbolInfo &symbol); //--- Check Freeze and Stops levels bool FreezeStopsLevels(double &level); //--- Open position void OpenPosition(const int index,const double level); //--- Open Buy position void OpenBuy(const int index,double sl,double tp); //--- Open Sell position void OpenSell(const int index,double sl,double tp); //--- Print CTrade result void PrintResultTrade(CTrade &trade,CSymbolInfo &symbol); //--- Get value of buffers bool iGetArray(const int handle,const int buffer,const int start_pos, const int count,double &arr_buffer[]); //--- Trailing void Trailing(const double stop_level); //--- Print CTrade result void PrintResultModify(CTrade &trade,CSymbolInfo &symbol,CPositionInfo &position); //--- Close positions void ClosePositions(const ENUM_POSITION_TYPE pos_type,const double level); //--- Calculate all positions void CalculateAllPositions(int &count_buys,double &volume_buys,double &volume_biggest_buys, int &count_sells,double &volume_sells,double &volume_biggest_sells); //--- Search trading signals bool SearchTradingSignals(void); //--- Calculate all volumes void CalculateAllVolumes(double &volumne_buys,double &volumne_sells, double &volumne_buy_limits,double &volumne_sell_limits, double &volumne_buy_stops,double &volumne_sell_stops); //--- Is position exists bool IsPositionExists(void); //--- Close all positions void CloseAllPositions(const double level); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTradingEngine31::CTradingEngine31() : m_stop_loss(0.0), m_take_profit(0.0), m_trailing_frequency(10), m_signals_frequency(9), m_trailing_stop(0.0), m_trailing_step(0.0), m_lot_or_risk(lots_min), m_volume_lot_or_risk(3.0), m_deviation(10), m_only_one(false), m_reverse(false), m_close_opposite(false), m_print_log(false), m_magic(200), m_max_positions(5), handle_iRSI(INVALID_HANDLE), m_adjusted_point(0.0), m_need_close_all(false), m_last_trailing(0), m_last_signal(0), m_prev_bars(0), m_last_deal_in(0), m_bar_current(1) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CTradingEngine31::~CTradingEngine31() { } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int CTradingEngine31::OnInit( ushort _StopLoss, // Stop Loss, in pips (1.00045-1.00055=1 pips) ushort _TakeProfit, // Take Profit, in pips (1.00045-1.00055=1 pips) ushort _TrailingFrequency, // Trailing, in seconds (< "10" -> only on a new bar) ushort _SignalsFrequency, // Search signals, in seconds (< "10" -> only on a new bar) ushort _TrailingStop, // Trailing Stop (min distance from price to Stop Loss, in pips ushort _TrailingStep, // Trailing Step, in pips (1.00045-1.00055=1 pips) ENUM_LOT_OR_RISK _LotOrRisk, // Money management: Lot OR Risk double _VolumeLotOrRisk, // The value for "Money management" ENUM_TRADE_MODE _TradeMode, // Trade mode: string __RSI_symbol, // RSI symbol int __RSI_ma_period, // RSI averaging period ENUM_APPLIED_PRICE __RSI_applied_price, // RSI type of price uchar _MaxPositions, // Maximum positions ulong _Deviation, // Deviation, in points (1.00045-1.00055=10 points) bool _OnlyOne, // Only one positions bool _Reverse, // Reverse bool _CloseOpposite, // Close opposite bool _PrintLog, // Print log ulong _Magic // Magic number ) { if(!m_symbol.Name(__RSI_symbol)) // sets symbol name return(INIT_FAILED); RefreshRates(); //--- tuning for 3 or 5 digits int digits_adjust=1; if(m_symbol.Digits()==3 || m_symbol.Digits()==5) digits_adjust=10; m_adjusted_point=m_symbol.Point()*digits_adjust; //--- m_stop_loss = _StopLoss * m_adjusted_point; m_take_profit = _TakeProfit * m_adjusted_point; m_trailing_frequency = _TrailingFrequency; m_signals_frequency = _SignalsFrequency; m_trailing_stop = _TrailingStop * m_adjusted_point; m_trailing_step = _TrailingStep * m_adjusted_point; m_lot_or_risk = _LotOrRisk; m_volume_lot_or_risk = _VolumeLotOrRisk; m_trade_mode = _TradeMode; m_deviation = _Deviation; m_only_one = _OnlyOne; m_reverse = _Reverse; m_close_opposite = _CloseOpposite; m_print_log = _PrintLog; m_magic = _Magic; m_max_positions = _MaxPositions; //--- m_trade.SetExpertMagicNumber(m_magic); m_trade.SetMarginMode(); m_trade.SetTypeFillingBySymbol(m_symbol.Name()); m_trade.SetDeviationInPoints(m_deviation); //--- check the input parameter "Lots" string err_text=""; if(m_lot_or_risk==lot) { if(!CheckVolumeValue(m_volume_lot_or_risk,err_text)) { //--- when testing, we will only output to the log about incorrect input parameters if(MQLInfoInteger(MQL_TESTER)) { Print(__FUNCTION__,", ERROR: ",err_text); return(INIT_FAILED); } else // if the Expert Advisor is run on the chart, tell the user about the error { Alert(__FUNCTION__,", ERROR: ",err_text); return(INIT_PARAMETERS_INCORRECT); } } } else { if(m_money!=NULL) delete m_money; m_money=new CMoneyFixedMargin; if(m_money!=NULL) { if(m_volume_lot_or_risk<1 || m_volume_lot_or_risk>100) { Print("The value for \"Money management\" (",DoubleToString(m_volume_lot_or_risk,2),") -> invalid parameters"); Print(" parameter must be in the range: from 1.00 to 100.00"); return(INIT_FAILED); } if(!m_money.Init(GetPointer(m_symbol),Period(),m_symbol.Point()*digits_adjust)) return(INIT_FAILED); m_money.Percent(m_volume_lot_or_risk); } else { Print(__FUNCTION__,", ERROR: Object CMoneyFixedMargin is NULL"); return(INIT_FAILED); } } //--- create handle of the indicator iRSI handle_iRSI=iRSI(m_symbol.Name(),Period(),__RSI_ma_period,__RSI_applied_price); //--- if the handle is not created if(handle_iRSI==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iRSI indicator for the symbol %s/%s, error code %d", m_symbol.Name(), EnumToString(Period()), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } //--- m_bar_current=(m_signals_frequency<10)?1:0; //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void CTradingEngine31::OnDeinit(const int reason) { //--- if(m_money!=NULL) delete m_money; } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void CTradingEngine31::OnTick(void) { if(m_need_close_all) { if(IsPositionExists()) { double level; if(FreezeStopsLevels(level)) { CloseAllPositions(level); return; } else return; } else m_need_close_all=false; } //--- int size_need_position=ArraySize(SPosition); if(size_need_position>0) { for(int i=size_need_position-1; i>=0; i--) { if(SPosition[i].waiting_transaction) { if(!SPosition[i].transaction_confirmed) { if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","transaction_confirmed: ",SPosition[i].transaction_confirmed); return; } else if(SPosition[i].transaction_confirmed) { ArrayRemove(SPosition,i,1); return; } } if(SPosition[i].pos_type==POSITION_TYPE_BUY) { if(m_close_opposite || m_only_one || m_max_positions>0) { int count_buys = 0; double volume_buys = 0.0; double volume_biggest_buys = 0.0; int count_sells = 0; double volume_sells = 0.0; double volume_biggest_sells = 0.0; CalculateAllPositions(count_buys,volume_buys,volume_biggest_buys, count_sells,volume_sells,volume_biggest_sells); if(m_close_opposite) { if(count_sells>0) { double level; if(FreezeStopsLevels(level)) ClosePositions(POSITION_TYPE_SELL,level); return; } } if(m_only_one) { if(count_buys+count_sells==0) { double level; if(FreezeStopsLevels(level)) { SPosition[i].waiting_transaction=true; OpenPosition(i,level); } return; } else ArrayRemove(SPosition,i,1); return; } if(m_max_positions>0) { if(count_buys+count_sells0) { int count_buys = 0; double volume_buys = 0.0; double volume_biggest_buys = 0.0; int count_sells = 0; double volume_sells = 0.0; double volume_biggest_sells = 0.0; CalculateAllPositions(count_buys,volume_buys,volume_biggest_buys, count_sells,volume_sells,volume_biggest_sells); if(m_close_opposite) { if(count_buys>0) { double level; if(FreezeStopsLevels(level)) ClosePositions(POSITION_TYPE_BUY,level); return; } } if(m_only_one) { if(count_buys+count_sells==0) { double level; if(FreezeStopsLevels(level)) { SPosition[i].waiting_transaction=true; OpenPosition(i,level); } return; } else ArrayRemove(SPosition,i,1); return; } if(m_max_positions>0) { if(count_buys+count_sells=10) // trailing no more than once every 10 seconds { datetime time_current=TimeCurrent(); if(time_current-m_last_trailing>10) { double level; if(FreezeStopsLevels(level)) Trailing(level); else return; m_last_trailing=time_current; } } if(m_signals_frequency>=10) // search for trading signals no more than once every 10 seconds { datetime time_current=TimeCurrent(); if(time_current-m_last_signal>10) { //--- search for trading signals if(!RefreshRates()) { m_prev_bars=0; return; } if(!SearchTradingSignals()) { m_prev_bars=0; return; } m_last_signal=time_current; } } //--- we work only at the time of the birth of new bar datetime time_0=iTime(m_symbol.Name(),Period(),0); if(time_0==m_prev_bars) return; m_prev_bars=time_0; if(m_trailing_frequency<10) // trailing only at the time of the birth of new bar { double level; if(FreezeStopsLevels(level)) Trailing(level); } if(m_signals_frequency<10) // search for trading signals only at the time of the birth of new bar { if(!RefreshRates()) { m_prev_bars=0; return; } //--- search for trading signals if(!SearchTradingSignals()) { m_prev_bars=0; return; } } //--- } //+------------------------------------------------------------------+ //| TradeTransaction function | //+------------------------------------------------------------------+ void CTradingEngine31::OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) { //--- get transaction type as enumeration value ENUM_TRADE_TRANSACTION_TYPE type=trans.type; //--- if transaction is result of addition of the transaction in history if(type==TRADE_TRANSACTION_DEAL_ADD) { if(HistoryDealSelect(trans.deal)) m_deal.Ticket(trans.deal); else return; if(m_deal.Symbol()==m_symbol.Name() && m_deal.Magic()==m_magic) { if(m_deal.DealType()==DEAL_TYPE_BUY || m_deal.DealType()==DEAL_TYPE_SELL) { if(m_deal.Entry()==DEAL_ENTRY_IN || m_deal.Entry()==DEAL_ENTRY_INOUT) m_last_deal_in=iTime(m_symbol.Name(),Period(),0); int size_need_position=ArraySize(SPosition); if(size_need_position>0) { for(int i=0; imax_volume) { if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian") error_description=StringFormat("Объем больше максимально допустимого SYMBOL_VOLUME_MAX=%.2f",max_volume); else error_description=StringFormat("Volume is greater than the maximal allowed SYMBOL_VOLUME_MAX=%.2f",max_volume); return(false); } //--- get minimal step of volume changing double volume_step=m_symbol.LotsStep(); int ratio=(int)MathRound(volume/volume_step); if(MathAbs(ratio*volume_step-volume)>0.0000001) { if(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian") error_description=StringFormat("Объем не кратен минимальному шагу SYMBOL_VOLUME_STEP=%.2f, ближайший правильный объем %.2f", volume_step,ratio*volume_step); else error_description=StringFormat("Volume is not a multiple of the minimal step SYMBOL_VOLUME_STEP=%.2f, the closest correct volume is %.2f", volume_step,ratio*volume_step); return(false); } error_description="Correct volume value"; return(true); } //+------------------------------------------------------------------+ //| Lot Check | //+------------------------------------------------------------------+ double CTradingEngine31::LotCheck(double lots,CSymbolInfo &symbol) { //--- calculate maximum volume double volume=NormalizeDouble(lots,2); double stepvol=symbol.LotsStep(); if(stepvol>0.0) volume=stepvol*MathFloor(volume/stepvol); //--- double minvol=symbol.LotsMin(); if(volumemaxvol) volume=maxvol; return(volume); } //+------------------------------------------------------------------+ //| Check Freeze and Stops levels | //+------------------------------------------------------------------+ bool CTradingEngine31::FreezeStopsLevels(double &level) { //--- check Freeze and Stops levels /* Type of order/position | Activation price | Check ------------------------|--------------------|-------------------------------------------- Buy Limit order | Ask | Ask-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL Buy Stop order | Ask | OpenPrice-Ask >= SYMBOL_TRADE_FREEZE_LEVEL Sell Limit order | Bid | OpenPrice-Bid >= SYMBOL_TRADE_FREEZE_LEVEL Sell Stop order | Bid | Bid-OpenPrice >= SYMBOL_TRADE_FREEZE_LEVEL Buy position | Bid | TakeProfit-Bid >= SYMBOL_TRADE_FREEZE_LEVEL | | Bid-StopLoss >= SYMBOL_TRADE_FREEZE_LEVEL Sell position | Ask | Ask-TakeProfit >= SYMBOL_TRADE_FREEZE_LEVEL | | StopLoss-Ask >= SYMBOL_TRADE_FREEZE_LEVEL Buying is done at the Ask price | Selling is done at the Bid price ------------------------------------------------|---------------------------------- TakeProfit >= Bid | TakeProfit <= Ask StopLoss <= Bid | StopLoss >= Ask TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL | Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL */ if(!RefreshRates() || !m_symbol.Refresh()) return(false); //--- FreezeLevel -> for pending order and modification double freeze_level=m_symbol.FreezeLevel()*m_symbol.Point(); if(freeze_level==0.0) freeze_level=(m_symbol.Ask()-m_symbol.Bid())*3.0; //--- StopsLevel -> for TakeProfit and StopLoss double stop_level=m_symbol.StopsLevel()*m_symbol.Point(); if(stop_level==0.0) stop_level=(m_symbol.Ask()-m_symbol.Bid())*3.0; if(freeze_level<=0.0 || stop_level<=0.0) return(false); level=(freeze_level>stop_level)?freeze_level:stop_level; double spread=m_symbol.Spread()*m_symbol.Point()*3.0; level=(level>spread)?level:spread; //--- return(true); } //+------------------------------------------------------------------+ //| Open position | //| double stop_loss | //| -> pips * m_adjusted_point (if "0.0" -> the m_stop_loss) | //| double take_profit | //| -> pips * m_adjusted_point (if "0.0" -> the m_take_profit) | //+------------------------------------------------------------------+ void CTradingEngine31::OpenPosition(const int index,const double level) { /* Buying is done at the Ask price | Selling is done at the Bid price ------------------------------------------------|---------------------------------- TakeProfit >= Bid | TakeProfit <= Ask StopLoss <= Bid | StopLoss >= Ask TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL | Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL */ //--- buy if(SPosition[index].pos_type==POSITION_TYPE_BUY) { double sl=(m_stop_loss==0.0)?0.0:m_symbol.Ask()-m_stop_loss; if(sl>0.0) if(m_symbol.Bid()-sl0.0) if(tp-m_symbol.Ask()0.0) if(sl-m_symbol.Ask()0.0) if(m_symbol.Bid()-tp0.0) long_lot=SPosition[index].volume; else { if(m_lot_or_risk==risk) { long_lot=m_money.CheckOpenLong(m_symbol.Ask(),sl); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","sl=",DoubleToString(sl,m_symbol.Digits()), ", CheckOpenLong: ",DoubleToString(long_lot,2), ", Balance: ", DoubleToString(m_account.Balance(),2), ", Equity: ", DoubleToString(m_account.Equity(),2), ", FreeMargin: ", DoubleToString(m_account.FreeMargin(),2)); if(long_lot==0.0) { ArrayRemove(SPosition,index,1); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","CMoneyFixedMargin.CheckOpenLong returned the value of 0.0"); return; } } else if(m_lot_or_risk==lot) long_lot=m_volume_lot_or_risk; else if(m_lot_or_risk==lots_min) long_lot=m_symbol.LotsMin(); else { ArrayRemove(SPosition,index,1); return; } } if(SPosition[index].lot_coefficient>0.0) { long_lot=LotCheck(long_lot*SPosition[index].lot_coefficient, m_symbol); if(long_lot==0) { ArrayRemove(SPosition,index,1); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","LotCheck returned the 0.0"); return; } } if(m_symbol.LotsLimit()>0.0) { int count_buys = 0; double volume_buys = 0.0; double volume_biggest_buys = 0.0; int count_sells = 0; double volume_sells = 0.0; double volume_biggest_sells = 0.0; CalculateAllPositions(count_buys,volume_buys,volume_biggest_buys, count_sells,volume_sells,volume_biggest_sells); if(volume_buys+volume_sells+long_lot>m_symbol.LotsLimit()) { ArrayRemove(SPosition,index,1); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","#0 Buy, Volume Buy (",DoubleToString(volume_buys,2), ") + Volume Sell (",DoubleToString(volume_sells,2), ") + Volume long (",DoubleToString(long_lot,2), ") > Lots Limit (",DoubleToString(m_symbol.LotsLimit(),2),")"); return; } } //--- check volume before OrderSend to avoid "not enough money" error (CTrade) double free_margin_check=m_account.FreeMarginCheck(m_symbol.Name(), ORDER_TYPE_BUY, long_lot, m_symbol.Ask()); double margin_check=m_account.MarginCheck(m_symbol.Name(), ORDER_TYPE_BUY, long_lot, m_symbol.Ask()); if(free_margin_check>margin_check) { if(m_trade.Buy(long_lot,m_symbol.Name(), m_symbol.Ask(),sl,tp)) // CTrade::Buy -> "true" { if(m_trade.ResultDeal()==0) { if(m_trade.ResultRetcode()==10009) // trade order went to the exchange { SPosition[index].waiting_transaction=true; SPosition[index].waiting_order_ticket=m_trade.ResultOrder(); } else { SPosition[index].waiting_transaction=false; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","#1 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); } if(m_print_log) PrintResultTrade(m_trade,m_symbol); } else { if(m_trade.ResultRetcode()==10009) { SPosition[index].waiting_transaction=true; SPosition[index].waiting_order_ticket=m_trade.ResultOrder(); } else { SPosition[index].waiting_transaction=false; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","#2 Buy -> true. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); } if(m_print_log) PrintResultTrade(m_trade,m_symbol); } } else { SPosition[index].waiting_transaction=false; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","#3 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(m_print_log) PrintResultTrade(m_trade,m_symbol); } } else { ArrayRemove(SPosition,index,1); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","CAccountInfo.FreeMarginCheck returned the value ",DoubleToString(free_margin_check,2)); return; } //--- } //+------------------------------------------------------------------+ //| Open Sell position | //+------------------------------------------------------------------+ void CTradingEngine31::OpenSell(const int index,double sl,double tp) { sl=m_symbol.NormalizePrice(sl); tp=m_symbol.NormalizePrice(tp); double short_lot=0.0; if(SPosition[index].volume>0.0) short_lot=SPosition[index].volume; else { if(m_lot_or_risk==risk) { short_lot=m_money.CheckOpenShort(m_symbol.Bid(),sl); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","sl=",DoubleToString(sl,m_symbol.Digits()), ", CheckOpenLong: ",DoubleToString(short_lot,2), ", Balance: ", DoubleToString(m_account.Balance(),2), ", Equity: ", DoubleToString(m_account.Equity(),2), ", FreeMargin: ", DoubleToString(m_account.FreeMargin(),2)); if(short_lot==0.0) { ArrayRemove(SPosition,index,1); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","CMoneyFixedMargin.CheckOpenShort returned the value of \"0.0\""); return; } } else if(m_lot_or_risk==lot) short_lot=m_volume_lot_or_risk; else if(m_lot_or_risk==lots_min) short_lot=m_symbol.LotsMin(); else { ArrayRemove(SPosition,index,1); return; } } if(SPosition[index].lot_coefficient>0.0) { short_lot=LotCheck(short_lot*SPosition[index].lot_coefficient,m_symbol); if(short_lot==0) { ArrayRemove(SPosition,index,1); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","LotCheck returned the 0.0"); return; } } if(m_symbol.LotsLimit()>0.0) { int count_buys = 0; double volume_buys = 0.0; double volume_biggest_buys = 0.0; int count_sells = 0; double volume_sells = 0.0; double volume_biggest_sells = 0.0; CalculateAllPositions(count_buys,volume_buys,volume_biggest_buys, count_sells,volume_sells,volume_biggest_sells); if(volume_buys+volume_sells+short_lot>m_symbol.LotsLimit()) { ArrayRemove(SPosition,index,1); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","#0 Buy, Volume Buy (",DoubleToString(volume_buys,2), ") + Volume Sell (",DoubleToString(volume_sells,2), ") + Volume short (",DoubleToString(short_lot,2), ") > Lots Limit (",DoubleToString(m_symbol.LotsLimit(),2),")"); return; } } //--- check volume before OrderSend to avoid "not enough money" error (CTrade) double free_margin_check=m_account.FreeMarginCheck(m_symbol.Name(), ORDER_TYPE_SELL, short_lot, m_symbol.Bid()); double margin_check=m_account.MarginCheck(m_symbol.Name(), ORDER_TYPE_SELL, short_lot, m_symbol.Bid()); if(free_margin_check>margin_check) { if(m_trade.Sell(short_lot,m_symbol.Name(), m_symbol.Bid(),sl,tp)) // CTrade::Sell -> "true" { if(m_trade.ResultDeal()==0) { if(m_trade.ResultRetcode()==10009) // trade order went to the exchange { SPosition[index].waiting_transaction=true; SPosition[index].waiting_order_ticket=m_trade.ResultOrder(); } else { SPosition[index].waiting_transaction=false; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","#1 Sell -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); } if(m_print_log) PrintResultTrade(m_trade,m_symbol); } else { if(m_trade.ResultRetcode()==10009) { SPosition[index].waiting_transaction=true; SPosition[index].waiting_order_ticket=m_trade.ResultOrder(); } else { SPosition[index].waiting_transaction=false; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","#2 Sell -> true. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); } if(m_print_log) PrintResultTrade(m_trade,m_symbol); } } else { SPosition[index].waiting_transaction=false; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","#3 Sell -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(m_print_log) PrintResultTrade(m_trade,m_symbol); } } else { ArrayRemove(SPosition,index,1); if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","CAccountInfo.FreeMarginCheck returned the value ",DoubleToString(free_margin_check,2)); return; } //--- } //+------------------------------------------------------------------+ //| Print CTrade result | //+------------------------------------------------------------------+ void CTradingEngine31::PrintResultTrade(CTrade &trade,CSymbolInfo &symbol) { Print(__FILE__," ",__FUNCTION__,", Symbol: ",symbol.Name()+", "+ "Code of request result: "+IntegerToString(trade.ResultRetcode())+", "+ "Code of request result as a string: "+trade.ResultRetcodeDescription()); Print("Deal ticket: "+IntegerToString(trade.ResultDeal())+", "+ "Order ticket: "+IntegerToString(trade.ResultOrder())+", "+ "Order retcode external: "+IntegerToString(trade.ResultRetcodeExternal())+", "+ "Volume of deal or order: "+DoubleToString(trade.ResultVolume(),2)); Print("Price, confirmed by broker: "+DoubleToString(trade.ResultPrice(),symbol.Digits())+", "+ "Current bid price: "+DoubleToString(symbol.Bid(),symbol.Digits())+" (the requote): "+DoubleToString(trade.ResultBid(),symbol.Digits())+", "+ "Current ask price: "+DoubleToString(symbol.Ask(),symbol.Digits())+" (the requote): "+DoubleToString(trade.ResultAsk(),symbol.Digits())); Print("Broker comment: "+trade.ResultComment()); } //+------------------------------------------------------------------+ //| Get value of buffers | //+------------------------------------------------------------------+ bool CTradingEngine31::iGetArray(const int handle,const int buffer,const int start_pos, const int count,double &arr_buffer[]) { bool result=true; if(!ArrayIsDynamic(arr_buffer)) { if(m_print_log) PrintFormat("ERROR! EA: %s, FUNCTION: %s, this a no dynamic array!",__FILE__,__FUNCTION__); return(false); } ArrayFree(arr_buffer); //--- reset error code ResetLastError(); //--- fill a part of the iBands array with values from the indicator buffer int copied=CopyBuffer(handle,buffer,start_pos,count,arr_buffer); if(copied!=count) { //--- if the copying fails, tell the error code if(m_print_log) PrintFormat("ERROR! EA: %s, FUNCTION: %s, amount to copy: %d, copied: %d, error code %d", __FILE__,__FUNCTION__,count,copied,GetLastError()); //--- quit with zero result - it means that the indicator is considered as not calculated return(false); } return(result); } //+------------------------------------------------------------------+ //| Trailing | //| InpTrailingStop: min distance from price to Stop Loss | //+------------------------------------------------------------------+ void CTradingEngine31::Trailing(const double stop_level) { /* Buying is done at the Ask price | Selling is done at the Bid price ------------------------------------------------|---------------------------------- TakeProfit >= Bid | TakeProfit <= Ask StopLoss <= Bid | StopLoss >= Ask TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL | Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL */ if(m_trailing_stop==0) return; for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of open positions if(m_position.SelectByIndex(i)) if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic) { double price_current = m_position.PriceCurrent(); double price_open = m_position.PriceOpen(); double stop_loss = m_position.StopLoss(); double take_profit = m_position.TakeProfit(); double ask = m_symbol.Ask(); double bid = m_symbol.Bid(); //--- if(m_position.PositionType()==POSITION_TYPE_BUY) { if(price_current-price_open>m_trailing_stop+m_trailing_step) if(stop_loss=stop_level && (take_profit-bid>=stop_level || take_profit==0.0)) { if(!m_trade.PositionModify(m_position.Ticket(), m_symbol.NormalizePrice(price_current-m_trailing_stop), take_profit)) if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","Modify BUY ",m_position.Ticket(), " Position -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(m_print_log) { RefreshRates(); m_position.SelectByIndex(i); PrintResultModify(m_trade,m_symbol,m_position); } continue; } } else { if(price_open-price_current>m_trailing_stop+m_trailing_step) if((stop_loss>(price_current+(m_trailing_stop+m_trailing_step))) || (stop_loss==0)) if(m_trailing_stop>=stop_level && ask-take_profit>=stop_level) { if(!m_trade.PositionModify(m_position.Ticket(), m_symbol.NormalizePrice(price_current+m_trailing_stop), take_profit)) if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","Modify SELL ",m_position.Ticket(), " Position -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(m_print_log) { RefreshRates(); m_position.SelectByIndex(i); PrintResultModify(m_trade,m_symbol,m_position); } } } } } //+------------------------------------------------------------------+ //| Print CTrade result | //+------------------------------------------------------------------+ void CTradingEngine31::PrintResultModify(CTrade &trade,CSymbolInfo &symbol,CPositionInfo &position) { Print("File: ",__FILE__,", symbol: ",symbol.Name()); Print("Code of request result: "+IntegerToString(trade.ResultRetcode())); Print("code of request result as a string: "+trade.ResultRetcodeDescription()); Print("Deal ticket: "+IntegerToString(trade.ResultDeal())); Print("Order ticket: "+IntegerToString(trade.ResultOrder())); Print("Volume of deal or order: "+DoubleToString(trade.ResultVolume(),2)); Print("Price, confirmed by broker: "+DoubleToString(trade.ResultPrice(),symbol.Digits())); Print("Current bid price: "+DoubleToString(symbol.Bid(),symbol.Digits())+" (the requote): "+DoubleToString(trade.ResultBid(),symbol.Digits())); Print("Current ask price: "+DoubleToString(symbol.Ask(),symbol.Digits())+" (the requote): "+DoubleToString(trade.ResultAsk(),symbol.Digits())); Print("Broker comment: "+trade.ResultComment()); Print("Freeze Level: "+DoubleToString(symbol.FreezeLevel(),0),", Stops Level: "+DoubleToString(symbol.StopsLevel(),0)); Print("Price of position opening: "+DoubleToString(position.PriceOpen(),symbol.Digits())); Print("Price of position's Stop Loss: "+DoubleToString(position.StopLoss(),symbol.Digits())); Print("Price of position's Take Profit: "+DoubleToString(position.TakeProfit(),symbol.Digits())); Print("Current price by position: "+DoubleToString(position.PriceCurrent(),symbol.Digits())); } //+------------------------------------------------------------------+ //| Close positions | //+------------------------------------------------------------------+ void CTradingEngine31::ClosePositions(const ENUM_POSITION_TYPE pos_type,const double level) { /* Buying is done at the Ask price | Selling is done at the Bid price ------------------------------------------------|---------------------------------- TakeProfit >= Bid | TakeProfit <= Ask StopLoss <= Bid | StopLoss >= Ask TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL | Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL */ for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic) if(m_position.PositionType()==pos_type) { if(m_position.PositionType()==POSITION_TYPE_BUY) { bool take_profit_level=(m_position.TakeProfit()!=0.0 && m_position.TakeProfit()-m_position.PriceCurrent()>=level) || m_position.TakeProfit()==0.0; bool stop_loss_level=(m_position.StopLoss()!=0.0 && m_position.PriceCurrent()-m_position.StopLoss()>=level) || m_position.StopLoss()==0.0; if(take_profit_level && stop_loss_level) if(!m_trade.PositionClose(m_position.Ticket())) // close a position by the specified m_symbol if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","CTrade.PositionClose ",m_position.Ticket()); } if(m_position.PositionType()==POSITION_TYPE_SELL) { bool take_profit_level=(m_position.TakeProfit()!=0.0 && m_position.PriceCurrent()-m_position.TakeProfit()>=level) || m_position.TakeProfit()==0.0; bool stop_loss_level=(m_position.StopLoss()!=0.0 && m_position.StopLoss()-m_position.PriceCurrent()>=level) || m_position.StopLoss()==0.0; if(!m_trade.PositionClose(m_position.Ticket())) // close a position by the specified m_symbol if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","CTrade.PositionClose ",m_position.Ticket()); } } } //+------------------------------------------------------------------+ //| Calculate all positions | //+------------------------------------------------------------------+ void CTradingEngine31::CalculateAllPositions(int &count_buys,double &volume_buys,double &volume_biggest_buys, int &count_sells,double &volume_sells,double &volume_biggest_sells) { count_buys = 0; volume_buys = 0.0; volume_biggest_buys = 0.0; count_sells = 0; volume_sells = 0.0; volume_biggest_sells = 0.0; for(int i=PositionsTotal()-1; i>=0; i--) if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties if(m_position.Symbol()==m_symbol.Name()) { if(m_position.PositionType()==POSITION_TYPE_BUY) { count_buys++; volume_buys+=m_position.Volume(); if(m_position.Volume()>volume_biggest_buys) volume_biggest_buys=m_position.Volume(); continue; } else if(m_position.PositionType()==POSITION_TYPE_SELL) { count_sells++; volume_sells+=m_position.Volume(); if(m_position.Volume()>volume_biggest_sells) volume_biggest_sells=m_position.Volume(); } } } //+------------------------------------------------------------------+ //| Search trading signals | //+------------------------------------------------------------------+ bool CTradingEngine31::SearchTradingSignals(void) { double rsi[]; ArraySetAsSeries(rsi,true); int start_pos=0,count=6; if(!iGetArray(handle_iRSI,0,start_pos,count,rsi)) { return(false); } int size_need_position=ArraySize(SPosition); if(rsi[m_bar_current+1]<30.0 && rsi[m_bar_current]>30.0) { if(!m_reverse) { if(m_trade_mode!=sell) { if(m_prev_bars==m_last_deal_in) // on one bar - only one deal return(true); ArrayResize(SPosition,size_need_position+1); SPosition[size_need_position].pos_type=POSITION_TYPE_BUY; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY"); return(true); } } else { if(m_trade_mode!=buy) { if(m_prev_bars==m_last_deal_in) // on one bar - only one deal return(true); ArrayResize(SPosition,size_need_position+1); SPosition[size_need_position].pos_type=POSITION_TYPE_SELL; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL"); return(true); } } } if(rsi[m_bar_current+1]>70.0 && rsi[m_bar_current]<70.0) { if(!m_reverse) { if(m_trade_mode!=buy) { if(m_prev_bars==m_last_deal_in) // on one bar - only one deal return(true); ArrayResize(SPosition,size_need_position+1); SPosition[size_need_position].pos_type=POSITION_TYPE_SELL; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal SELL"); return(true); } } else { if(m_trade_mode!=sell) { if(m_prev_bars==m_last_deal_in) // on one bar - only one deal return(true); ArrayResize(SPosition,size_need_position+1); SPosition[size_need_position].pos_type=POSITION_TYPE_BUY; if(m_print_log) Print(__FILE__," ",__FUNCTION__,", OK: ","Signal BUY"); return(true); } } } //--- return(true); } //+------------------------------------------------------------------+ //| Is position exists | //+------------------------------------------------------------------+ bool CTradingEngine31::IsPositionExists(void) { for(int i=PositionsTotal()-1; i>=0; i--) if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic) return(true); //--- return(false); } //+------------------------------------------------------------------+ //| Close all positions | //+------------------------------------------------------------------+ void CTradingEngine31::CloseAllPositions(const double level) { /* Buying is done at the Ask price | Selling is done at the Bid price ------------------------------------------------|---------------------------------- TakeProfit >= Bid | TakeProfit <= Ask StopLoss <= Bid | StopLoss >= Ask TakeProfit - Bid >= SYMBOL_TRADE_STOPS_LEVEL | Ask - TakeProfit >= SYMBOL_TRADE_STOPS_LEVEL Bid - StopLoss >= SYMBOL_TRADE_STOPS_LEVEL | StopLoss - Ask >= SYMBOL_TRADE_STOPS_LEVEL */ for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic) { if(m_position.PositionType()==POSITION_TYPE_BUY) { bool take_profit_level=(m_position.TakeProfit()!=0.0 && m_position.TakeProfit()-m_position.PriceCurrent()>=level) || m_position.TakeProfit()==0.0; bool stop_loss_level=(m_position.StopLoss()!=0.0 && m_position.PriceCurrent()-m_position.StopLoss()>=level) || m_position.StopLoss()==0.0; if(take_profit_level && stop_loss_level) if(!m_trade.PositionClose(m_position.Ticket())) // close a position by the specified m_symbol if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","CTrade.PositionClose ",m_position.Ticket()); } if(m_position.PositionType()==POSITION_TYPE_SELL) { bool take_profit_level=(m_position.TakeProfit()!=0.0 && m_position.PriceCurrent()-m_position.TakeProfit()>=level) || m_position.TakeProfit()==0.0; bool stop_loss_level=(m_position.StopLoss()!=0.0 && m_position.StopLoss()-m_position.PriceCurrent()>=level) || m_position.StopLoss()==0.0; if(take_profit_level && stop_loss_level) if(!m_trade.PositionClose(m_position.Ticket())) // close a position by the specified m_symbol if(m_print_log) Print(__FILE__," ",__FUNCTION__,", ERROR: ","CTrade.PositionClose ",m_position.Ticket()); } } } //+------------------------------------------------------------------+ //| Profit all positions | //+------------------------------------------------------------------+ double CTradingEngine31::ProfitAllPositions(void) { double profit=0.0; for(int i=PositionsTotal()-1; i>=0; i--) if(m_position.SelectByIndex(i)) // selects the position by index for further access to its properties if(m_position.Symbol()==m_symbol.Name() && m_position.Magic()==m_magic) profit+=m_position.Commission()+m_position.Swap()+m_position.Profit(); //--- return(profit); } //+------------------------------------------------------------------+