//+------------------------------------------------------------------+ //| MultiSymbol MACD signals.mq5 | //| Copyright © 2019, Vladimir Karputov | //| http://wmua.ru/slesar/ | //+------------------------------------------------------------------+ #property copyright "Copyright © 2019, Vladimir Karputov" #property link "http://wmua.ru/slesar/" #property version "1.000" #include #include CArrayObj m_array_obj; // CArrayObj object CSymbolInfo ClassSymbol; // symbol info object //+------------------------------------------------------------------+ //| Enum Lor or Risk | //+------------------------------------------------------------------+ enum ENUM_LOT_OR_RISK { lot=0, // Constant lot risk=1, // Risk in percent for a deal }; //+------------------------------------------------------------------+ //| Structure Need Positions | //+------------------------------------------------------------------+ struct STRUCT_NEED_POSITION { ENUM_POSITION_TYPE pos_type; // position type double volume; // position volume (if "0.0" -> the lot is "Money management") double stop_loss; // position stop loss (if "0.0" -> the "Stop Loss, in pips") bool waiting_transaction; // waiting transaction, "true" -> it's forbidden to trade, we expect a transaction ulong waiting_order_ticket; // waiting order ticket, ticket of the expected order bool transaction_confirmed; // transaction confirmed, "true" -> transaction confirmed //--- Constructor STRUCT_NEED_POSITION() { pos_type = WRONG_VALUE; volume = 0.0; stop_loss = 0.0; waiting_transaction = false; waiting_order_ticket = 0; transaction_confirmed = false; } }; //--- input parameters input string MasterSymbols="EURUSD,USDJPY,USDCAD"; // Symbols input ushort MasterStopLoss = 45; // Stop Loss, in pips (1.00045-1.00055=1 pips) input ushort MasterTakeProfit = 96; // Take Profit, in pips (1.00045-1.00055=1 pips) input ushort MasterTrailingFrequency = 10; // Trailing, in seconds (< "10" -> only on a new bar) input ushort MasterTrailingStop = 25; // Trailing Stop (min distance from price to Stop Loss, in pips input ushort MasterTrailingStep = 5; // Trailing Step, in pips (1.00045-1.00055=1 pips) input ENUM_LOT_OR_RISK MasterLotOrRisk = risk; // Money management: Lot OR Risk input double MasterVolumeLotOrRisk = 1.0; // The value for "Money management" //--- input bool MasterOnlyOne = true; // Only one positions input bool MasterCloseOpposite = true; // Close opposite input bool MasterPrintLog = false; // Print log input ulong MasterMagic = 40242548; // Magic number //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- string to_split=MasterSymbols; // a string to split into substrings StringTrimLeft(to_split); StringTrimRight(to_split); string sep=","; // a separator as a character ushort u_sep; // the code of the separator character string result[]; // an array to get strings //--- get the separator code u_sep=StringGetCharacter(sep,0); //--- split the string to substrings int k=StringSplit(to_split,u_sep,result); for(int i=0;i #include #include #include #include #include #include //--- //+------------------------------------------------------------------+ //| Class CTradingEngine3. | //| Appointment: Class Expert Advisor. | //| Derives from class CObject. | //+------------------------------------------------------------------+ class CTradingEngine3 : public CObject { protected: CPositionInfo m_position; // trade position object CTrade m_trade; // trading object CSymbolInfo m_symbol; // symbol info object CAccountInfo m_account; // account info wrapper CDealInfo m_deal; // deals object COrderInfo m_order; // pending orders object CMoneyFixedMargin *m_money; //--- input parameters ushort InpStopLoss; ushort InpTakeProfit; ushort InpTrailingFrequency; ushort InpTrailingStop; ushort InpTrailingStep; ENUM_LOT_OR_RISK InpLotOrRisk; double InpVolumeLotOrRisk; //--- bool InpOnlyOne; bool InpCloseOpposite; bool InpPrintLog; ulong InpMagic; //--- ulong ExtSlippage; double ExtStopLoss; double ExtTakeProfit; double ExtTrailingStop; double ExtTrailingStep; int m_handle_macd; // variable for storing the handle of the iMACD indicator double ExtAdjustedPoint; // point value adjusted for 3 or 5 points /* bool ExtNeedOpenBuy = false; bool ExtNeedOpenSell = false; */ datetime ExtLastTrailing; datetime ExtPrevBars; //--- STRUCT_NEED_POSITION SNeedPosition[]; public: CTradingEngine3(); ~CTradingEngine3(); //--- Expert initialization function int OnInit( string Symbol_, ushort StopLoss, ushort TakeProfit, ushort TrailingFrequency, ushort TrailingStop, ushort TrailingStep, ENUM_LOT_OR_RISK LotOrRisk, double VolumeLotOrRisk, bool OnlyOne, bool CloseOpposite, bool PrintLog, ulong Magic ); //--- 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); //--- Refreshes the symbol quotes data bool RefreshRates(void); //--- Check the correctness of the position volume bool CheckVolumeValue(double volume,string &error_description); //--- Check Freeze and Stops levels bool FreezeStopsLevels(double &level); //--- Open position void OpenPosition(const int index_in_structure,const ENUM_POSITION_TYPE pos_type, const double volume,const double stop_loss,const double level); //--- Open Buy position void OpenBuy(const int index_in_structure,const double volume,double sl,double tp); //--- Open Sell position void OpenSell(const int index_in_structure,const double volume,double sl,double tp); //--- Print CTrade result void PrintResultTrade(CTrade &trade,CSymbolInfo &symbol); //--- Get value of buffers double 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); }; //+------------------------------------------------------------------+ //| Constructor | //+------------------------------------------------------------------+ CTradingEngine3::CTradingEngine3() : InpStopLoss(15), InpTakeProfit(46), InpTrailingFrequency(10), InpTrailingStop(25), InpTrailingStep(5), InpLotOrRisk(risk), InpVolumeLotOrRisk(3.0), InpOnlyOne(true), InpCloseOpposite(true), InpPrintLog(false), InpMagic(200), ExtSlippage(10), ExtStopLoss(0.0), ExtTakeProfit(0.0), ExtTrailingStop(0.0), ExtTrailingStep(0.0), ExtLastTrailing(0), ExtPrevBars(0) { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ CTradingEngine3::~CTradingEngine3() { } //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int CTradingEngine3::OnInit( string Symbol_, ushort StopLoss, ushort TakeProfit, ushort TrailingFrequency, ushort TrailingStop, ushort TrailingStep, ENUM_LOT_OR_RISK LotOrRisk, double VolumeLotOrRisk, bool OnlyOne, bool CloseOpposite, bool PrintLog, ulong Magic ) { //--- initialization InpStopLoss = StopLoss; InpTakeProfit = TakeProfit; InpTrailingFrequency = TrailingFrequency; InpTrailingStop = TrailingStop; InpTrailingStep = TrailingStep; InpLotOrRisk = LotOrRisk; InpVolumeLotOrRisk = VolumeLotOrRisk; InpOnlyOne = OnlyOne; InpCloseOpposite = CloseOpposite; InpPrintLog = PrintLog; InpMagic = Magic; //--- if(InpTrailingStop!=0 && InpTrailingStep==0) { string err_text=(TerminalInfoString(TERMINAL_LANGUAGE)=="Russian")? "Трейлинг невозможен: параметр \"Trailing Step\" равен нулю!": "Trailing is not possible: parameter \"Trailing Step\" is zero!"; //--- 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); } } //--- if(!m_symbol.Name(Symbol_)) // sets symbol name return(INIT_FAILED); RefreshRates(); //--- m_trade.SetExpertMagicNumber(InpMagic); m_trade.SetMarginMode(); m_trade.SetTypeFillingBySymbol(m_symbol.Name()); m_trade.SetDeviationInPoints(ExtSlippage); //--- tuning for 3 or 5 digits int digits_adjust=1; if(m_symbol.Digits()==3 || m_symbol.Digits()==5) digits_adjust=10; ExtAdjustedPoint=m_symbol.Point()*digits_adjust; ExtStopLoss = InpStopLoss * ExtAdjustedPoint; ExtTakeProfit = InpTakeProfit * ExtAdjustedPoint; ExtTrailingStop = InpTrailingStop * ExtAdjustedPoint; ExtTrailingStep = InpTrailingStep * ExtAdjustedPoint; //--- check the input parameter "Lots" string err_text=""; if(InpLotOrRisk==lot) { if(!CheckVolumeValue(InpVolumeLotOrRisk,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(InpVolumeLotOrRisk<1 || InpVolumeLotOrRisk>100) { Print("The value for \"Money management\" (",DoubleToString(InpVolumeLotOrRisk,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(InpVolumeLotOrRisk); } else { Print(__FUNCTION__,", ERROR: Object CMoneyFixedMargin is NULL"); return(INIT_FAILED); } } //--- create handle of the indicator iMACD m_handle_macd=iMACD(m_symbol.Name(),Period(),12,26,9,PRICE_CLOSE); //--- if the handle is not created if(m_handle_macd==INVALID_HANDLE) { //--- tell about the failure and output the error code PrintFormat("Failed to create handle of the iMACD indicator for the symbol %s/%s, error code %d", m_symbol.Name(), EnumToString(Period()), GetLastError()); //--- the indicator is stopped early return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ CTradingEngine3::OnDeinit(const int reason) { //--- if(m_money!=NULL) delete m_money; } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ CTradingEngine3::OnTick(void) { //--- int size_need_position=ArraySize(SNeedPosition); if(size_need_position>0) { for(int i=0;i0) { double level; if(FreezeStopsLevels(level)) ClosePositions(POSITION_TYPE_SELL,level); return; } } if(InpOnlyOne) { if(count_buys+count_sells==0) { double level; if(FreezeStopsLevels(level)) { SNeedPosition[i].waiting_transaction=true; OpenPosition(i,POSITION_TYPE_BUY,SNeedPosition[i].volume,SNeedPosition[i].stop_loss,level); } return; } else ArrayRemove(SNeedPosition,i,1); //--- return; } } //--- double level; if(FreezeStopsLevels(level)) { SNeedPosition[i].waiting_transaction=true; OpenPosition(i,POSITION_TYPE_BUY,SNeedPosition[i].volume,SNeedPosition[i].stop_loss,level); } //--- return; } if(SNeedPosition[i].pos_type==POSITION_TYPE_SELL) { if(InpCloseOpposite || InpOnlyOne) { 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(InpCloseOpposite) { if(count_buys>0) { double level; if(FreezeStopsLevels(level)) ClosePositions(POSITION_TYPE_BUY,level); return; } } if(InpOnlyOne) { if(count_buys+count_sells==0) { double level; if(FreezeStopsLevels(level)) { SNeedPosition[i].waiting_transaction=true; OpenPosition(i,POSITION_TYPE_SELL,SNeedPosition[i].volume,SNeedPosition[i].stop_loss,level); } return; } else ArrayRemove(SNeedPosition,i,1); //--- return; } } //--- double level; if(FreezeStopsLevels(level)) { SNeedPosition[i].waiting_transaction=true; OpenPosition(i,POSITION_TYPE_SELL,SNeedPosition[i].volume,SNeedPosition[i].stop_loss,level); } //--- return; } } } if(InpTrailingFrequency>=10) // trailing no more than once every 10 seconds { datetime time_current=TimeCurrent(); if(time_current-ExtLastTrailing>10) { double level; if(FreezeStopsLevels(level)) Trailing(level); ExtLastTrailing=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==ExtPrevBars) return; ExtPrevBars=time_0; if(!RefreshRates()) { ExtPrevBars=0; return; } if(InpTrailingFrequency<10) // trailing only at the time of the birth of new bar { double level; if(FreezeStopsLevels(level)) Trailing(level); } //--- search for trading signals if(!SearchTradingSignals()) { ExtPrevBars=0; return; } //--- } //+------------------------------------------------------------------+ //| TradeTransaction function | //+------------------------------------------------------------------+ CTradingEngine3::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) { long deal_ticket =0; long deal_order =0; long deal_time =0; long deal_time_msc =0; long deal_type =-1; long deal_entry =-1; long deal_magic =0; long deal_reason =-1; long deal_position_id =0; double deal_volume =0.0; double deal_price =0.0; double deal_commission =0.0; double deal_swap =0.0; double deal_profit =0.0; string deal_symbol =""; string deal_comment =""; string deal_external_id =""; if(HistoryDealSelect(trans.deal)) { deal_ticket =HistoryDealGetInteger(trans.deal,DEAL_TICKET); deal_order =HistoryDealGetInteger(trans.deal,DEAL_ORDER); deal_time =HistoryDealGetInteger(trans.deal,DEAL_TIME); deal_time_msc =HistoryDealGetInteger(trans.deal,DEAL_TIME_MSC); deal_type =HistoryDealGetInteger(trans.deal,DEAL_TYPE); deal_entry =HistoryDealGetInteger(trans.deal,DEAL_ENTRY); deal_magic =HistoryDealGetInteger(trans.deal,DEAL_MAGIC); deal_reason =HistoryDealGetInteger(trans.deal,DEAL_REASON); deal_position_id =HistoryDealGetInteger(trans.deal,DEAL_POSITION_ID); deal_volume =HistoryDealGetDouble(trans.deal,DEAL_VOLUME); deal_price =HistoryDealGetDouble(trans.deal,DEAL_PRICE); deal_commission =HistoryDealGetDouble(trans.deal,DEAL_COMMISSION); deal_swap =HistoryDealGetDouble(trans.deal,DEAL_SWAP); deal_profit =HistoryDealGetDouble(trans.deal,DEAL_PROFIT); deal_symbol =HistoryDealGetString(trans.deal,DEAL_SYMBOL); deal_comment =HistoryDealGetString(trans.deal,DEAL_COMMENT); deal_external_id =HistoryDealGetString(trans.deal,DEAL_EXTERNAL_ID); } else return; ENUM_DEAL_ENTRY enum_deal_entry=(ENUM_DEAL_ENTRY)deal_entry; if(deal_symbol==m_symbol.Name() && deal_magic==InpMagic) { if(deal_type==DEAL_TYPE_BUY || deal_type==DEAL_TYPE_SELL) { int size_need_position=ArraySize(SNeedPosition); 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); } //+------------------------------------------------------------------+ //| Check Freeze and Stops levels | //+------------------------------------------------------------------+ bool CTradingEngine3::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; freeze_level*=1.1; //--- 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; stop_level*=1.1; if(freeze_level<=0.0 || stop_level<=0.0) return(false); level=(freeze_level>stop_level)?freeze_level:stop_level; //--- return(true); } //+------------------------------------------------------------------+ //| Open position | //+------------------------------------------------------------------+ CTradingEngine3::OpenPosition(const int index_in_structure,const ENUM_POSITION_TYPE pos_type, const double volume,const double stop_loss,const double level) { //--- buy if(pos_type==POSITION_TYPE_BUY) { double price=m_symbol.Ask(); double sl=0.0; if(stop_loss==0.0) { sl=(InpStopLoss==0)?0.0:price-ExtStopLoss; if(sl!=0.0 && ExtStopLoss0.0) long_lot=volume; else { if(InpLotOrRisk==risk) { long_lot=m_money.CheckOpenLong(m_symbol.Ask(),sl); if(InpPrintLog) Print("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) { SNeedPosition[index_in_structure].waiting_transaction=false; if(InpPrintLog) Print(__FUNCTION__,", ERROR: method CheckOpenLong returned the value of \"0.0\""); return; } } else if(InpLotOrRisk==lot) long_lot=InpVolumeLotOrRisk; else { SNeedPosition[index_in_structure].waiting_transaction=false; 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()) { Print("#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_SELL,long_lot,m_symbol.Bid()); 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 { SNeedPosition[index_in_structure].waiting_transaction=true; SNeedPosition[index_in_structure].waiting_order_ticket=m_trade.ResultOrder(); } else SNeedPosition[index_in_structure].waiting_transaction=false; if(InpPrintLog) Print("#1 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(InpPrintLog) PrintResultTrade(m_trade,m_symbol); } else { if(m_trade.ResultRetcode()==10009) { SNeedPosition[index_in_structure].waiting_transaction=true; SNeedPosition[index_in_structure].waiting_order_ticket=m_trade.ResultOrder(); } else SNeedPosition[index_in_structure].waiting_transaction=false; if(InpPrintLog) Print("#2 Buy -> true. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(InpPrintLog) PrintResultTrade(m_trade,m_symbol); } } else { SNeedPosition[index_in_structure].waiting_transaction=false; if(InpPrintLog) Print("#3 Buy -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(InpPrintLog) PrintResultTrade(m_trade,m_symbol); } } else { ArrayRemove(SNeedPosition,index_in_structure,1); if(InpPrintLog) Print(__FUNCTION__,", ERROR: method CAccountInfo::FreeMarginCheck returned the value ",DoubleToString(free_margin_check,2)); return; } } //+------------------------------------------------------------------+ //| Open Sell position | //+------------------------------------------------------------------+ CTradingEngine3::OpenSell(const int index_in_structure,const double volume,double sl,double tp) { sl=m_symbol.NormalizePrice(sl); tp=m_symbol.NormalizePrice(tp); double short_lot=0.0; if(volume>0.0) short_lot=volume; else { if(InpLotOrRisk==risk) { short_lot=m_money.CheckOpenShort(m_symbol.Bid(),sl); if(InpPrintLog) Print("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) { SNeedPosition[index_in_structure].waiting_transaction=false; if(InpPrintLog) Print(__FUNCTION__,", ERROR: method CheckOpenShort returned the value of \"0.0\""); return; } } else if(InpLotOrRisk==lot) short_lot=InpVolumeLotOrRisk; else { SNeedPosition[index_in_structure].waiting_transaction=false; 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()) Print("#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 { SNeedPosition[index_in_structure].waiting_transaction=true; SNeedPosition[index_in_structure].waiting_order_ticket=m_trade.ResultOrder(); } else SNeedPosition[index_in_structure].waiting_transaction=false; if(InpPrintLog) Print("#1 Sell -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(InpPrintLog) PrintResultTrade(m_trade,m_symbol); } else { if(m_trade.ResultRetcode()==10009) { SNeedPosition[index_in_structure].waiting_transaction=true; SNeedPosition[index_in_structure].waiting_order_ticket=m_trade.ResultOrder(); } else SNeedPosition[index_in_structure].waiting_transaction=false; if(InpPrintLog) Print("#2 Sell -> true. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(InpPrintLog) PrintResultTrade(m_trade,m_symbol); } } else { SNeedPosition[index_in_structure].waiting_transaction=false; if(InpPrintLog) Print("#3 Sell -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); if(InpPrintLog) PrintResultTrade(m_trade,m_symbol); } } else { ArrayRemove(SNeedPosition,index_in_structure,1); if(InpPrintLog) Print(__FUNCTION__,", ERROR: method CAccountInfo::FreeMarginCheck returned the value ",DoubleToString(free_margin_check,2)); return; } } //+------------------------------------------------------------------+ //| Print CTrade result | //+------------------------------------------------------------------+ CTradingEngine3::PrintResultTrade(CTrade &trade,CSymbolInfo &symbol) { 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()); } //+------------------------------------------------------------------+ //| Get value of buffers | //+------------------------------------------------------------------+ double CTradingEngine3::iGetArray(const int handle,const int buffer,const int start_pos,const int count,double &arr_buffer[]) { bool result=true; if(!ArrayIsDynamic(arr_buffer)) { Print("This a no dynamic array!"); 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 PrintFormat("Failed to copy data from the indicator, error code %d",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 | //+------------------------------------------------------------------+ CTradingEngine3::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(InpTrailingStop==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()==InpMagic) { if(m_position.PositionType()==POSITION_TYPE_BUY) { if(m_position.PriceCurrent()-m_position.PriceOpen()>ExtTrailingStop+ExtTrailingStep) if(m_position.StopLoss()=stop_level) { if(!m_trade.PositionModify(m_position.Ticket(), m_symbol.NormalizePrice(m_position.PriceCurrent()-ExtTrailingStop), m_position.TakeProfit())) Print("Modify ",m_position.Ticket(), " Position -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); RefreshRates(); m_position.SelectByIndex(i); PrintResultModify(m_trade,m_symbol,m_position); continue; } } else { if(m_position.PriceOpen()-m_position.PriceCurrent()>ExtTrailingStop+ExtTrailingStep) if((m_position.StopLoss()>(m_position.PriceCurrent()+(ExtTrailingStop+ExtTrailingStep))) || (m_position.StopLoss()==0)) if(ExtTrailingStop>=stop_level) { if(!m_trade.PositionModify(m_position.Ticket(), m_symbol.NormalizePrice(m_position.PriceCurrent()+ExtTrailingStop), m_position.TakeProfit())) Print("Modify ",m_position.Ticket(), " Position -> false. Result Retcode: ",m_trade.ResultRetcode(), ", description of result: ",m_trade.ResultRetcodeDescription()); RefreshRates(); m_position.SelectByIndex(i); PrintResultModify(m_trade,m_symbol,m_position); } } } } //+------------------------------------------------------------------+ //| Print CTrade result | //+------------------------------------------------------------------+ CTradingEngine3::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())); int d=0; } //+------------------------------------------------------------------+ //| Close positions | //+------------------------------------------------------------------+ CTradingEngine3::ClosePositions(const ENUM_POSITION_TYPE pos_type,const double 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()==InpMagic) if(m_position.PositionType()==pos_type) { if(m_position.PositionType()==POSITION_TYPE_BUY) if(MathAbs(m_symbol.Bid()-m_position.PriceOpen())>=level) m_trade.PositionClose(m_position.Ticket()); // close a position by the specified symbol if(m_position.PositionType()==POSITION_TYPE_SELL) if(MathAbs(m_symbol.Ask()-m_position.PriceOpen())>=level) m_trade.PositionClose(m_position.Ticket()); // close a position by the specified symbol } } //+------------------------------------------------------------------+ //| Calculate all positions | //+------------------------------------------------------------------+ CTradingEngine3::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() && m_position.Magic()==InpMagic) { 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 CTradingEngine3::SearchTradingSignals(void) { double macd_main[],macd_signal[]; ArraySetAsSeries(macd_main,true); ArraySetAsSeries(macd_signal,true); int start_pos=0,count=3; if(!iGetArray(m_handle_macd,MAIN_LINE,start_pos,count,macd_main) || !iGetArray(m_handle_macd,SIGNAL_LINE,start_pos,count,macd_signal)) { return(false); } int size_need_position=ArraySize(SNeedPosition); if(macd_main[1]>macd_signal[1]) { ArrayResize(SNeedPosition,size_need_position+1); SNeedPosition[size_need_position].pos_type=POSITION_TYPE_BUY; //--- return(true); } if(macd_main[1]