//+------------------------------------------------------------------+ //| MACD Sample.mq4 | //| Copyright © 2005, MetaQuotes Software Corp. | //| http://www.metaquotes.net/ | //| | //| Improved by Robert Hill | //+------------------------------------------------------------------+ #include #include // Add defines for signals #define LONG 1 #define SHORT -1 #define FLAT 0 // Add defines for position status #define NONE 0 #define OPENED 1 #define CLOSED 2 // Add a magic number for better trade control extern int MagicBase = 200000; extern string Expert_Name = "MACD"; extern string ma1="-- Indicator settings--"; extern string ma2 = "-- MACD --"; extern int FastEMA_Period = 12; extern int SlowEMA_Period = 26; extern int Signal_Period = 9; extern double MACDOpenLevel=3; extern double MACDCloseLevel=2; extern string t = "--Moving Average --"; extern double MA_TrendPeriod=26; extern string tm = "--Moving Average Types--"; extern string tm0 = " 0 = SMA"; extern string tm1 = " 1 = EMA"; extern string tm2 = " 2 = SMMA"; extern string tm3 = " 3 = LWMA"; extern int MA_Type = 1; extern string tp = "--Applied Price Types--"; extern string tp0 = " 0 = close"; extern string tp1 = " 1 = open"; extern string tp2 = " 2 = high"; extern string tp3 = " 3 = low"; extern string tp4 = " 4 = median(high+low)/2"; extern string tp5 = " 5 = typical(high+low+close)/3"; extern string tp6 = " 6 = weighted(high+low+close+close)/4"; extern int MA_AppliedPrice = 0; extern string ob0 = "-- Trade on Open Candles --"; extern string ob1 = "Set SignalCandle to 0 for Open Candles"; extern string ob2 = "Set SignalCandle to 1 for Closed Candles"; extern int SignalCandle = 0; extern int Slippage = 3; extern double StopLoss=0; extern double TakeProfit = 50; extern string tsp = "--Trailing Stop Types--"; extern string tsp0 = " 0. None"; extern string tsp1 = " 1 = Trail immediately"; extern string tsp2 = " 2 = Wait to trail"; extern int TrailingStopType = 2; // Type 2 is the original trailing stop in MACD Sample extern string ts2 = "Settings for Type 2"; extern double TrailingStop = 30; // Change to whatever number of pips you wish to trail your position with. //+---------------------------------------------------+ //|Money Management | //+---------------------------------------------------+ extern string mm = "---Money Management---"; extern double Lots=0.1; extern bool UseMoneyManagement = false; extern bool BrokerIsIBFX = false; extern string m1="Set mini and micro to false for standard account"; extern bool AccountIsMini = true; extern bool AccountIsMicro = false; extern double TradeSizePercent = 1; // Change to whatever percent of equity you wish to risk. extern bool BrokerPermitsFractionalLots = true; int MagicNumber=0; string setup; double mLots; double myPoint; //+------------------------------------------------------------------+ //| Calculate MagicNumber, setup comment and assign RSI Period | //| | //+------------------------------------------------------------------+ int init() { MagicNumber = MagicBase + func_Symbol2Val(Symbol())*100 + func_TimeFrame_Const2Val(Period()); setup = Expert_Name + Symbol() + "_" + func_TimeFrame_Val2String(func_TimeFrame_Const2Val(Period())); myPoint = SetPoint(); return(0); } int deinit() { return(0); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int start() { int Position, signal; // initial data checks // it is important to make sure that the expert works with a normal // chart and the user did not make any mistakes setting external // variables (Lots, StopLoss, TakeProfit, // TrailingStop) in our case, we check TakeProfit // on a chart of less than 100 bars if(Bars<100) { Print("bars less than 100"); return(0); } if(TakeProfit<10) { Print("TakeProfit less than 10"); return(0); // check TakeProfit } RefreshRates(); //+------------------------------------------------------------------+ //| Check for Open Position | //+------------------------------------------------------------------+ // Only allow 1 trade per Symbol Position = HandleOpenPositions(); if (Position == OPENED) return(0); if (NewBar()) signal=GetSignal(); // wait until first tick after bar close to take any action; if (signal != FLAT) { mLots = GetLots(); if(AccountFreeMargin()<(1000*mLots)) { Print("We have no money. Free Margin = ", AccountFreeMargin()); return(0); } if(signal == LONG) OpenBuyOrder(mLots); if(signal == SHORT) OpenSellOrder(mLots); } return(0); } //+------------------------------------------------------------------+ //| GetSignal | //| | //+------------------------------------------------------------------+ int GetSignal() { double MacdCurrent, MacdPrevious, SignalCurrent; double SignalPrevious, MaCurrent, MaPrevious; // to simplify the coding and speed up access // data are put into internal variables MacdCurrent=iMACD(NULL,0,FastEMA_Period,SlowEMA_Period,Signal_Period,PRICE_CLOSE,MODE_MAIN,SignalCandle); MacdPrevious=iMACD(NULL,0,FastEMA_Period,SlowEMA_Period,Signal_Period,PRICE_CLOSE,MODE_MAIN,SignalCandle + 1); SignalCurrent=iMACD(NULL,0,FastEMA_Period,SlowEMA_Period,Signal_Period,PRICE_CLOSE,MODE_SIGNAL,SignalCandle); SignalPrevious=iMACD(NULL,0,FastEMA_Period,SlowEMA_Period,Signal_Period,PRICE_CLOSE,MODE_SIGNAL,SignalCandle + 1); MaCurrent=iMA(NULL,0,MA_TrendPeriod,0,MA_Type,MA_AppliedPrice,SignalCandle); MaPrevious=iMA(NULL,0,MA_TrendPeriod,0,MA_Type,MA_AppliedPrice,SignalCandle + 1); // check for long position (BUY) possibility if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious(MACDOpenLevel*myPoint) && MaCurrent>MaPrevious) { return(LONG); } // check for short position (SELL) possibility if(MacdCurrent>0 && MacdCurrentSignalPrevious && MacdCurrent>(MACDOpenLevel*myPoint) && MaCurrent 0 && MacdCurrent < SignalCurrent && MacdPrevious > SignalPrevious && MacdCurrent>(MACDCloseLevel*myPoint)) { return(true); } } if (cmd == OP_SELL) { if(MacdCurrent<0 && MacdCurrent>SignalCurrent && MacdPrevious(MACDCloseLevel*myPoint)) { return(true); } } return(false); } //+------------------------------------------------------------------+ //| OpenBuyOrder | //| If Stop Loss or TakeProfit are used the values are calculated | //| for each trade | //+------------------------------------------------------------------+ int OpenBuyOrder(double mLots) { int err,ticket; double TPprice,STprice; RefreshRates(); ticket=OrderSend(Symbol(),OP_BUY,mLots,Ask,Slippage,0,0,setup,MagicNumber,0,Green); if (ticket > 0) { if (OrderSelect( ticket,SELECT_BY_TICKET, MODE_TRADES) ) { Print("BUY order opened : ", OrderOpenPrice( )); if (StopLoss != 0 || TakeProfit != 0) { TPprice = 0; if (TakeProfit > 0) TPprice=TakeLong(OrderOpenPrice(), TakeProfit); STprice = 0; if (StopLoss > 0) { STprice=StopLong(OrderOpenPrice(), StopLoss); STprice = ValidStopLoss(OP_BUY,Bid, STprice); } // Normalize stoploss / takeprofit to the proper # of digits. if (Digits > 0) { STprice = NormalizeDouble( STprice, Digits); TPprice = NormalizeDouble( TPprice, Digits); } ModifyOrder(ticket, OrderOpenPrice(), STprice, TPprice, LightGreen); } } } else { err = GetLastError(); if(err==0) { return(ticket); } else { if(err==4 || err==137 ||err==146 || err==136) //Busy errors { Sleep(5000); } else //normal error { Print("Error opening BUY order [" + setup + "]: (" + err + ") " + ErrorDescription(err)); } } } return(ticket); } //+------------------------------------------------------------------+ //| OpenSellOrder | //| If Stop Loss or TakeProfit are used the values are calculated | //| for each trade | //+------------------------------------------------------------------+ void OpenSellOrder(double mLots) { int err, ticket; double TPprice,STprice; RefreshRates(); ticket=OrderSend(Symbol(),OP_SELL,mLots,Bid,Slippage,0,0,setup,MagicNumber,0,Red); if (ticket > 0) { if (OrderSelect( ticket,SELECT_BY_TICKET, MODE_TRADES) ) { Print("Sell order opened : ", OrderOpenPrice()); if (StopLoss != 0 || TakeProfit != 0) { TPprice = 0; if (TakeProfit > 0) TPprice=TakeShort(OrderOpenPrice(),TakeProfit); STprice = 0; if (StopLoss > 0) { STprice=StopShort(OrderOpenPrice() ,StopLoss); STprice = ValidStopLoss(OP_SELL,Ask, STprice); } // Normalize stoploss / takeprofit to the proper # of digits. if (Digits > 0) { STprice = NormalizeDouble( STprice, Digits); TPprice = NormalizeDouble( TPprice, Digits); } ModifyOrder(ticket, OrderOpenPrice(), STprice, TPprice, LightGreen); } } } else { err = GetLastError(); if(err==0) { return(ticket); } else { if(err==4 || err==137 ||err==146 || err==136) //Busy errors { Sleep(5000); } else //normal error { Print("Error opening Sell order [" + setup + "]: (" + err + ") " + ErrorDescription(err)); } } } return(ticket); } //+------------------------------------------------------------------+ //| Handle Open Positions | //| Check if any open positions need to be closed or modified | //+------------------------------------------------------------------+ int HandleOpenPositions() { int cnt; bool Closed = false; Closed = NONE; // it is important to enter the market correctly, // but it is more important to exit it correctly... // INPORTANT // This is an error in the original sample // It is necessary to close orders in reverse order because // When a position closes the other orders change position so some will not be closed. // for(cnt=0;cnt=0;cnt--) { OrderSelect (cnt, SELECT_BY_POS, MODE_TRADES); if ( OrderSymbol() != Symbol()) continue; if ( OrderMagicNumber() != MagicNumber) continue; Closed = OPENED; if(OrderType() == OP_BUY) { Closed = OPENED; // should it be closed? if (CheckExitCondition(OP_BUY)) { CloseOrder(OrderTicket(),OrderLots(),Bid, Green); Closed = CLOSED; } else { // check for trailing stop if (TrailingStopType > 0) { HandleTrailingStop(OP_BUY,OrderTicket(),OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit()); } } } if(OrderType() == OP_SELL) { Closed = OPENED; if (CheckExitCondition(OP_SELL)) // should it be closed? { CloseOrder(OrderTicket(),OrderLots(),Ask, Red); Closed = CLOSED; } else { if (TrailingStopType > 0) { HandleTrailingStop(OP_SELL,OrderTicket(),OrderOpenPrice(),OrderStopLoss(),OrderTakeProfit()); } } } } return(Closed); } int ModifyOrder(int ord_ticket,double op, double price,double tp, color mColor) { int CloseCnt, err; CloseCnt=0; while (CloseCnt < 3) { if (OrderModify(ord_ticket,op,price,tp,0,mColor)) { CloseCnt = 3; } else { err=GetLastError(); Print(CloseCnt," Error modifying order : (", err , ") " + ErrorDescription(err)); if (err>0) CloseCnt++; } } } int CloseOrder(int ord_ticket, double myLots, double price, color mColor) { int CloseCnt, err; CloseCnt=0; while (CloseCnt < 3) { if (OrderClose(ord_ticket,myLots,price,Slippage,mColor)) { CloseCnt = 3; } else { err=GetLastError(); Print(CloseCnt," Error closing order : (", err , ") " + ErrorDescription(err)); if (err>0) CloseCnt++; } } } double ValidStopLoss(int type, double price, double SL) { double minstop; double newSL; minstop = MarketInfo(Symbol(),MODE_STOPLEVEL); if (Digits == 3 || Digits == 5) minstop = minstop / 10; newSL = SL; if (type == OP_BUY) { if((price - SL) < minstop*myPoint) newSL = price - minstop*myPoint; } if (type == OP_SELL) { if((SL-price) < minstop*myPoint) newSL = price + minstop*myPoint; } newSL = NormalizeDouble(newSL,Digits); return(newSL); } //+------------------------------------------------------------------+ //| HandleTrailingStop | //| Type 1 moves the stoploss without delay. | //| Type 2 waits for price to move the amount of the trailStop | //| before moving stop loss then moves like type 1 | //| Type 3 uses up to 3 levels for trailing stop | //| Level 1 Move stop to 1st level | //| Level 2 Move stop to 2nd level | //| Level 3 Trail like type 1 by fixed amount other than 1 | //| Type 4 Move stop to breakeven + Lockin, no trail | //| Type 5 uses steps for 1, every step pip move moves stop 1 pip | //| Type 6 Uses EMA to set trailing stop | //| Type 7 Uses Paraboloc SAR | //| Type 8 Uses Parabolic SAR coded by bluto from original EA | //+------------------------------------------------------------------+ int HandleTrailingStop(int type, int ticket, double op, double os, double tp) { switch (TrailingStopType) { case 1 : Immediate_TrailingStop (type, ticket, op, os, tp); break; case 2 : Delayed_TrailingStop (type, ticket, op, os, tp); break; } return(0); } //+------------------------------------------------------------------+ //| Immediate_TrailingStop.mq4 | //| Copyright © 2006, Forex-TSD.com | //| Written by MrPip,robydoby314@yahoo.com | //| | //| Moves the stoploss without delay. | //+------------------------------------------------------------------+ void Immediate_TrailingStop(int type, int ticket, double op, double os, double tp) { int digits; double pt, pBid, pAsk, BuyStop, SellStop; digits = MarketInfo(Symbol( ), MODE_DIGITS); if (type==OP_BUY) { pBid = MarketInfo(Symbol(), MODE_BID); pt = StopLoss * myPoint; if(pBid-os > pt) { BuyStop = pBid - pt; if (digits > 0) BuyStop = NormalizeDouble( BuyStop, digits); BuyStop = ValidStopLoss(OP_BUY,pBid, BuyStop); if (os < BuyStop) ModifyOrder(ticket,op,BuyStop,tp,LightGreen); return; } } if (type==OP_SELL) { pAsk = MarketInfo(Symbol(), MODE_ASK); pt = StopLoss * myPoint; if(os - pAsk > pt) { SellStop = pAsk + pt; if (digits > 0) SellStop = NormalizeDouble( SellStop, digits); SellStop = ValidStopLoss(OP_SELL, pAsk, SellStop); if (os > SellStop) ModifyOrder(ticket,op,SellStop,tp,DarkOrange); return; } } } //+------------------------------------------------------------------+ //| Delayed_TrailingStop.mq4 | //| Copyright © 2006, Forex-TSD.com | //| Written by MrPip,robydoby314@yahoo.com | //| | //| Waits for price to move the amount of the TrailingStop | //| Moves the stoploss pip for pip after delay. | //+------------------------------------------------------------------+ void Delayed_TrailingStop(int type, int ticket, double op, double os, double tp) { int digits; double pt, pBid, pAsk, BuyStop, SellStop; pt = TrailingStop * myPoint; digits = MarketInfo(Symbol(), MODE_DIGITS); if (type==OP_BUY) { pBid = MarketInfo(Symbol(), MODE_BID); BuyStop = pBid - pt; if (digits > 0) BuyStop = NormalizeDouble( BuyStop, digits); BuyStop = ValidStopLoss(OP_BUY,pBid, BuyStop); if (pBid-op > pt && os < BuyStop) ModifyOrder(ticket,op,BuyStop,tp,LightGreen); return; } if (type==OP_SELL) { pAsk = MarketInfo(Symbol(), MODE_ASK); pt = TrailingStop * myPoint; SellStop = pAsk + pt; if (digits > 0) SellStop = NormalizeDouble( SellStop, digits); SellStop = ValidStopLoss(OP_SELL, pAsk, SellStop); if (op - pAsk > pt && os > SellStop) ModifyOrder(ticket,op,SellStop,tp,DarkOrange); return; } } //+------------------------------------------------------------------+ //| Get number of lots for this trade | //+------------------------------------------------------------------+ double GetLots() { double lot; double myMaxLot = MarketInfo(Symbol(), MODE_MAXLOT); if (UseMoneyManagement == false) return(Lots); if (BrokerIsIBFX == true) { lot = Calc_IBFX_Money_Management(); return(lot); } // lot = LotsOptimized(); lot=NormalizeDouble((AccountEquity()*TradeSizePercent/10000)/10,2); // lot = MathRound( lot/myStep ) * myStep; // Use at least 1 micro lot if (AccountIsMicro == true) { lot = MathFloor(lot*100)/100; if (lot < 0.01) lot = 0.01; if (lot > myMaxLot) lot = myMaxLot; return(lot); } // Use at least 1 mini lot if(AccountIsMini == true) { lot = MathFloor(lot*10)/10; if (lot < 0.1) lot = 0.1; if (lot > myMaxLot) lot = myMaxLot; return(lot); } // Standard account if( BrokerPermitsFractionalLots == false) { if (lot >= 1.0) lot = MathFloor(lot); else lot = 1.0; } if (lot < 1.0) lot = 1.0; if (lot > myMaxLot) lot = myMaxLot; return(lot); } double Calc_IBFX_Money_Management() { // variables used for money management double lot; double myMaxLot = MarketInfo(Symbol(), MODE_MAXLOT); lot=NormalizeDouble((AccountEquity()*TradeSizePercent/10000)/10,2); // Use at least 1 micro lot if (AccountIsMicro == true) { lot = lot * 10; lot = MathFloor(lot*100)/100; if (lot < 0.1) lot = 0.1; if (lot > myMaxLot) lot = myMaxLot; return(lot); } // Use at least 1 mini lot if(AccountIsMini == true) { lot = lot * 10; lot = MathFloor(lot*10)/10; if (lot < 1) lot = 1; if (lot > myMaxLot) lot = myMaxLot; return(lot); } // Standard Account if(BrokerPermitsFractionalLots == true) lot = StrToDouble(DoubleToStr(lot, 2)); else lot = MathFloor(lot); if (lot > myMaxLot) lot = myMaxLot; return(lot); } double StopLong(double price,int stop) { if(stop==0) return(0); else return(price-(stop*myPoint)); } double StopShort(double price,int stop) { if(stop==0) return(0); else return(price+(stop*myPoint)); } double TakeLong(double price,int take) { if(take==0) return(0); else return(price+(take*myPoint)); } double TakeShort(double price,int take) { if(take==0) return(0); else return(price-(take*myPoint)); } int func_Symbol2Val(string symbol) { string mySymbol = StringSubstr(symbol,0,6); if(mySymbol=="AUDCAD") return(1); if(mySymbol=="AUDJPY") return(2); if(mySymbol=="AUDNZD") return(3); if(mySymbol=="AUDUSD") return(4); if(mySymbol=="CHFJPY") return(5); if(mySymbol=="EURAUD") return(6); if(mySymbol=="EURCAD") return(7); if(mySymbol=="EURCHF") return(8); if(mySymbol=="EURGBP") return(9); if(mySymbol=="EURJPY") return(10); if(mySymbol=="EURUSD") return(11); if(mySymbol=="GBPCHF") return(12); if(mySymbol=="GBPJPY") return(13); if(mySymbol=="GBPUSD") return(14); if(mySymbol=="NZDJPY") return(15); if(mySymbol=="NZDUSD") return(16); if(mySymbol=="USDCAD") return(17); if(mySymbol=="USDCHF") return(18); if(mySymbol=="USDJPY") return(19); Comment("unexpected Symbol"); return(999); } //+------------------------------------------------------------------+ //| Time frame interval appropriation function | //+------------------------------------------------------------------+ int func_TimeFrame_Const2Val(int Constant ) { switch(Constant) { case 1: // M1 return(1); case 5: // M5 return(2); case 15: return(3); case 30: return(4); case 60: return(5); case 240: return(6); case 1440: return(7); case 10080: return(8); case 43200: return(9); } } //+------------------------------------------------------------------+ //| Time frame string appropriation function | //+------------------------------------------------------------------+ string func_TimeFrame_Val2String(int Value ) { switch(Value) { case 1: // M1 return("PERIOD_M1"); case 2: // M1 return("PERIOD_M5"); case 3: return("PERIOD_M15"); case 4: return("PERIOD_M30"); case 5: return("PERIOD_H1"); case 6: return("PERIOD_H4"); case 7: return("PERIOD_D1"); case 8: return("PERIOD_W1"); case 9: return("PERIOD_MN1"); default: return("undefined " + Value); } } double SetPoint() { double mPoint; if (Digits < 4) mPoint = 0.01; else mPoint = 0.0001; return(mPoint); } bool NewBar() { static datetime dt = 0; if (Time[0] != dt) { dt = Time[0]; return(true); } return(false); }