//+------------------------------------------------------------------+ //| StandartFunctions.mqh | //| AHMAD KAZBAR | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "AHMAD KAZBAR" #property version "1.00" #include #include //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class CBar : public CObject { public: double c; double o; double h; double l; datetime t; int i; bool p ; string type; CBar(double _c,double _o,double _h,double _l,datetime _t,int _i,string _type,bool peak) { c = _c; o = _o; h = _h; l = _l; t= _t; i = _i; p = peak; type = _type; } bool Equals(double val,double val2) { return val == val2; } }; struct STradeSum { int count; double profit; double trailPrice; }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ class StandartFunctions { private: string m_symbol; ENUM_TIMEFRAMES m_timeFrame; int m_digits; CTrade m_trade; long m_magic; datetime previous_time; bool m_print_log; public: StandartFunctions(string symbol,ENUM_TIMEFRAMES timeFrame,long exMagic,bool p_log = false) { m_symbol = symbol; m_timeFrame = timeFrame; m_magic = exMagic; m_digits = (int)SymbolInfoInteger(m_symbol,SYMBOL_DIGITS); m_trade.SetExpertMagicNumber(exMagic); IsNewBar(); m_print_log = p_log; } StandartFunctions(); ~StandartFunctions(); bool IsNewBar(); bool IsNewBarDay(); double High(int shift); double Close(int shift); double Low(int shift); double Open(int shift); datetime Time(int shift); double Bid(); double Ask(); double PipeToDouble(double pips); double CalculateLotByBalance(); double tr(int shifit); double CalculatePipsFromDollars(double dollarAmount,double lotSize); double CalcLots(double slPoints); double Size(int shift); ulong BuyLimit(double lot,double entry,double stop,double tp,string comment,datetime expirt); ulong SellLimit(double lot,double entry,double stop,double tp,string comment,datetime expirt); ulong BuyStop(double lot,double entry,double stop,double tp,string comment,datetime expirt); ulong SellStop(double lot,double entry,double stop,double tp,string comment,datetime expirt); ulong OpenOrder(ENUM_ORDER_TYPE OrderType,double lot,double entry,double stop,double tp,string comment); void UpdatePosition(double trailingPips,double target); bool UpdatePosition(const ulong ticket,const double sl,const double tp); void GetTradeSum(STradeSum &sum,ENUM_POSITION_TYPE type); void DrawArrow(string name, datetime arrowTime, double arrowPrice, string direction = "up", color clr = clrLime, int size = 2); bool IsPivotHigh(int index,int Left,int Right,const MqlRates &m_rates[]); bool IsPivotLow(int index,int Left,int Right,const MqlRates &m_rates[]); bool CheckTradeAllowed(); ENUM_TIMEFRAMES GetTimeFrame(){return m_timeFrame;} }; //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ StandartFunctions::StandartFunctions() { } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ StandartFunctions::~StandartFunctions() { } //+------------------------------------------------------------------+ double StandartFunctions::High(int shift) {return iHigh(m_symbol,m_timeFrame,shift);} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::Low(int shift) {return iLow(m_symbol,m_timeFrame,shift);} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::Close(int shift) {return iClose(m_symbol,m_timeFrame,shift);} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::Open(int shift) {return iOpen(m_symbol,m_timeFrame,shift);} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ datetime StandartFunctions::Time(int shift) {return iTime(m_symbol,m_timeFrame,shift);} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::Ask(void) { return NormalizeDouble(SymbolInfoDouble(m_symbol,SYMBOL_ASK),m_digits);} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::Bid(void) { return NormalizeDouble(SymbolInfoDouble(m_symbol,SYMBOL_ASK),m_digits);} //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void StandartFunctions::GetTradeSum(STradeSum &sum,ENUM_POSITION_TYPE type) { sum.count = 0; sum.profit = 0.0; sum.trailPrice = 0.0; int count = PositionsTotal(); if(count <=0) return; for(int i = OrdersTotal()-1; i >= 0; i--) { COrderInfo order; if(order.SelectByIndex(i)) { if(order.Magic() != m_magic) continue; if(order.Symbol() != m_symbol) continue; ///Print(__FUNCTION__," > Found pending order with ticket #",order.Ticket(),"..."); if(order.OrderType() == ORDER_TYPE_BUY_LIMIT) sum.count++; if(order.OrderType() == ORDER_TYPE_SELL_LIMIT) sum.count++; } } for(int i = count-1; i>=0; i--) { ulong ticket = PositionGetTicket(i); if(ticket>0) { if(PositionGetInteger(POSITION_TYPE) == type) { sum.count++; sum.profit += PositionGetDouble(POSITION_PROFIT)+PositionGetDouble(POSITION_SWAP); double entry = PositionGetDouble(POSITION_PRICE_OPEN); double profit = PositionGetDouble(POSITION_PROFIT); if(type==POSITION_TYPE_BUY) { if(sum.trailPrice==0 || PositionGetDouble(POSITION_PRICE_OPEN)sum.trailPrice) { sum.trailPrice = PositionGetDouble(POSITION_PRICE_OPEN); } } } } } return; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool StandartFunctions::IsNewBar(void) { datetime current_time = iTime(m_symbol,m_timeFrame,0); if(previous_time != current_time) { previous_time = current_time; return true; } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool StandartFunctions::IsNewBarDay(void) { static datetime prevTime = 0; datetime currentTime = iTime(m_symbol,PERIOD_D1,0); if(prevTime == currentTime) return false; prevTime = currentTime; return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::tr(int shift) { double t1 = High(shift) - Low(shift) ; double t2 = MathAbs(High(shift) - Close(shift+1)); double t3 = MathAbs(Low(shift) - Close(shift+1)); return MathMax(MathMax(t1, t2), t3); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::Size(int shift) { double totalSize = High(shift) - Low(shift); double totalSize2 = High(shift+1) - Low(shift+1); return totalSize/totalSize2; } //+------------------------------------------------------------------+ double StandartFunctions::PipeToDouble(double pips) { return NormalizeDouble(PointsToDouble(m_symbol,pips),m_digits); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ulong StandartFunctions::OpenOrder(ENUM_ORDER_TYPE OrderType,double lot,double entry,double stoploos,double tp,string comment) { ulong result =-1; if(CanOpenOrder(m_symbol,OrderType,lot,entry)) { if(!m_trade.PositionOpen(m_symbol,OrderType,lot,entry,stoploos,tp,comment)) return -1; else return m_trade.ResultOrder(); } else { return -1; } return -1; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ulong StandartFunctions::BuyLimit(double lot,double entry,double stoploos,double tp,string comment,datetime expirt) { if(!m_trade.BuyLimit(lot,entry,m_symbol,stoploos,tp,ORDER_TIME_GTC,expirt,comment)) return -1; ulong result = m_trade.ResultOrder(); return result; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ulong StandartFunctions::BuyStop(double lot,double entry,double stoploos,double tp,string comment,datetime expirt) { if(!m_trade.BuyStop(lot,entry,m_symbol,stoploos,tp,ORDER_TIME_GTC,expirt,comment)) return -1; return m_trade.ResultDeal(); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ulong StandartFunctions::SellLimit(double lot,double entry,double stoploos,double tp,string comment,datetime expirt) { if(!m_trade.SellLimit(lot,entry,m_symbol,stoploos,tp,ORDER_TIME_GTC,expirt,comment)) return -1; ulong result = m_trade.ResultOrder(); return result; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ ulong StandartFunctions::SellStop(double lot,double entry,double stoploos,double tp,string comment,datetime expirt) { if(!m_trade.SellStop(lot,entry,m_symbol,stoploos,tp,ORDER_TIME_GTC,expirt,comment)) return -1; return m_trade.ResultDeal(); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool StandartFunctions::UpdatePosition(const ulong ticket,const double sl,const double tp) { return m_trade.PositionModify(ticket,sl,tp); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void StandartFunctions::DrawArrow(string name, datetime arrowTime, double arrowPrice, string dir = "up", color clr = clrLime, int size = 2) { string objName = name + "_" + dir + "_" + TimeToString(arrowTime, TIME_SECONDS); if(!ObjectCreate(0, objName, OBJ_ARROW, 0, arrowTime, arrowPrice)) return; int arrowCode = (dir == "down") ? 234 : 233; // 233 = up, 234 = down color arrowColor = (dir == "down") ? clrRed : clr; ObjectSetInteger(0, objName, OBJPROP_ARROWCODE, arrowCode); ObjectSetInteger(0, objName, OBJPROP_COLOR, arrowColor); ObjectSetInteger(0, objName, OBJPROP_WIDTH, size); ObjectSetInteger(0, objName, OBJPROP_BACK, false); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::CalculateLotByBalance() { // 1) Get current account balance double balance = AccountInfoDouble(ACCOUNT_BALANCE); // 2) Compute how many “$100” increments int increments = int(balance / 100.0); // e.g.: if balance=250.75 → increments = floor(250.75/100) = 2 // 3) Base lot = increments * 0.01 double lot = increments * 0.01; // e.g.: 2 * 0.01 = 0.02 // 4) Fetch symbol’s min/max/step volume double minLot = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MIN); double maxLot = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_MAX); double step = SymbolInfoDouble(m_symbol, SYMBOL_VOLUME_STEP); // 5) If computed lot < minimum, set to minLot if(lot < minLot) lot = minLot; // 6) Round “lot” down to nearest multiple of “step” // e.g. if step=0.01 and lot=0.027, MathFloor(0.027/0.01)=2 → 2*0.01=0.02 if(step > 0.0) lot = MathFloor(lot / step) * step; // 7) If that rounding pushed lot > maxLot, clamp to maxLot if(lot > maxLot) lot = maxLot; return(lot); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool StandartFunctions::CheckTradeAllowed() { MqlDateTime date_cur; TimeTradeServer(date_cur); datetime seconds_cur = date_cur.hour * 3600 + date_cur.min * 60 + date_cur.sec; int i = 0; while(true) { datetime seconds_from = {}, seconds_to = {}; if(!SymbolInfoSessionTrade(m_symbol, (ENUM_DAY_OF_WEEK)date_cur.day_of_week, i, seconds_from, seconds_to)) break; if(seconds_cur > seconds_from && seconds_cur < seconds_to) return true; ++i; } return false; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void StandartFunctions::UpdatePosition(double trailingPips,double target) { int total = PositionsTotal(); for(int i = total-1; i >= 0; i--) { ulong position_ticket = PositionGetTicket(i); string m_pair = ""; double m_lot = 0.0; double m_profit = 0.0; double m_stopLoos = 0.0; double m_open_price = 0.0; double m_tp = 0.0; long m_position_type; long magic; double m_point; double m_bid; double m_ask; if( !PositionGetString(POSITION_SYMBOL,m_pair) || !PositionGetDouble(POSITION_VOLUME,m_lot) || !PositionGetDouble(POSITION_PROFIT,m_profit)|| !PositionGetDouble(POSITION_PRICE_OPEN,m_open_price)|| !PositionGetInteger(POSITION_MAGIC,magic)|| !PositionGetDouble(POSITION_TP,m_tp)|| !PositionGetDouble(POSITION_SL,m_stopLoos)) { return; Print("POSITION_SYMBOL ERROR"); } if(m_symbol != m_pair && m_magic != magic) return; if( !SymbolInfoDouble(m_pair, SYMBOL_BID,m_bid)|| !SymbolInfoDouble(m_pair, SYMBOL_ASK,m_ask)|| !SymbolInfoDouble(m_pair, SYMBOL_POINT,m_point)) { return; Print("SYMBOL_DIGITS ERROR"); } if(!PositionGetInteger(POSITION_TYPE,m_position_type)) { return; Print("POSITION_TYPE ERROR"); } string m_position_name = m_position_type == POSITION_TYPE_BUY ? "BUY" :m_position_type == POSITION_TYPE_SELL ? "SELL" : "UNKOWN"; if(m_position_name == "UNKOWN") { Print("POSITION_TYPE ERROR"); return; } NormalizeDouble(m_bid,(int)m_digits); NormalizeDouble(m_ask,(int)m_digits); NormalizeDouble(m_profit,(int)m_digits); NormalizeDouble(m_stopLoos,(int)m_digits); NormalizeDouble(m_tp,(int)m_digits); NormalizeDouble(m_open_price,(int)m_digits); //double close = Close(1,m_pair,PERIOD_M5); double buy_stop = m_bid - trailingPips ; double sell_stop = m_ask + trailingPips ; //double atr = tr(0,m_pair,PERIOD_H1); //Print( // StringFormat( // "Pair:%s,Position:%s,Open:%.2f,Profit:%-.*f,StopLoos:%.2f,Lot:%.2f", // m_pair,m_position_name,m_open_price,m_digits,m_profit,m_stopLoos,m_lot) //); //Print(StringFormat("buy:%-.*f,sell:%-.*f,m_avg:%.2f,latAvg:%.2f",m_digits,buy_stop,m_digits,sell_stop,m_avg,m_lastAvg)); if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_BUY) { if(m_profit >= target) { double dollarToPip = NormalizeDouble(CalculatePipsFromDollars(m_profit,m_lot),(int)m_digits); //m_trade.PositionClose(position_ticket); } if(buy_stop > m_stopLoos && buy_stop > m_open_price) { if(m_trade.PositionModify(position_ticket,buy_stop,m_tp)) Print("PositionModify"); else Print(_LastError); } //if(m_profit >= trailingPips*3) // m_trade.PositionClose(position_ticket); } if(PositionGetInteger(POSITION_TYPE) == POSITION_TYPE_SELL) { if(m_profit >= target) { double dollarToPip = NormalizeDouble(CalculatePipsFromDollars(m_profit,m_lot),(int)m_digits); //m_trade.PositionClose(position_ticket); } if(m_stopLoos == 0) { if(sell_stop < m_open_price) { if(m_trade.PositionModify(position_ticket,sell_stop,m_tp)) Print("PositionModify"); else Print(_LastError); } } else if(sell_stop < m_stopLoos && sell_stop < m_open_price) { if(m_trade.PositionModify(position_ticket,sell_stop,m_tp)) Print("PositionModify"); else Print(_LastError); } //if(m_profit >= trailingPips*3) // m_trade.PositionClose(position_ticket); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::CalcLots(double slPoints) { double risk = AccountInfoDouble(ACCOUNT_BALANCE) * 10 / 100; double ticksize = SymbolInfoDouble(m_symbol,SYMBOL_TRADE_TICK_SIZE); double tickvalue = SymbolInfoDouble(m_symbol,SYMBOL_TRADE_TICK_VALUE); double lotstep = SymbolInfoDouble(m_symbol,SYMBOL_VOLUME_STEP); double moneyPerLotstep = slPoints / ticksize * tickvalue * lotstep; double lots = MathFloor(risk / moneyPerLotstep) * lotstep; lots = MathMin(lots,SymbolInfoDouble(m_symbol,SYMBOL_VOLUME_MAX)); lots = MathMax(lots,SymbolInfoDouble(m_symbol,SYMBOL_VOLUME_MIN)); return lots; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double StandartFunctions::CalculatePipsFromDollars(double dollarAmount,double lotSize) { double tickSize = SymbolInfoDouble(m_symbol, SYMBOL_TRADE_TICK_SIZE); double tickValue = SymbolInfoDouble(m_symbol, SYMBOL_TRADE_TICK_VALUE); double point = SymbolInfoDouble(m_symbol, SYMBOL_POINT); int digits = (int)SymbolInfoInteger(m_symbol, SYMBOL_DIGITS); double pipValue = tickValue / tickSize * point; double pips = dollarAmount / (pipValue * lotSize); return pips; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool StandartFunctions::IsPivotHigh(int index,int Left,int Right,const MqlRates &rates[]) { for(int j = 1; j <= Right; j++) if(rates[index].high <= rates[index - j].high) return false; for(int j = 1; j <= Right; j++) if(rates[index].high <= rates[index + j].high) return false; return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool StandartFunctions::IsPivotLow(int index,int Left,int Right,const MqlRates &rates[]) { for(int j = 1; j <= Left; j++) if(rates[index].low >= rates[index - j].low) return false; for(int j = 1; j <= Right; j++) if(rates[index].low>= rates[index + j].low) return false; return true; } //+------------------------------------------------------------------+ int PipsToPoint(string symbol,double pips) { int D = (int) SymbolInfoInteger(symbol,SYMBOL_DIGITS); return (int)(pips* ((D==3 || D==5) ? 10 : 1)); } //+------------------------------------------------------------------+ double PointsToDouble(string symbol,double point) { Print(SymbolInfoDouble(symbol,SYMBOL_POINT)); return (point * SymbolInfoDouble(symbol,SYMBOL_POINT)); } //+------------------------------------------------------------------+ bool CanOpenOrder(string symbol,ENUM_ORDER_TYPE OrderType,double lot,double entry) { double margin = 0.0; if(!OrderCalcMargin(OrderType, symbol, lot, entry, margin)) { return false; } double freeMargin = AccountInfoDouble(ACCOUNT_MARGIN_FREE); if(margin > freeMargin) { return false; } return true; } //+------------------------------------------------------------------+