//+------------------------------------------------------------------+ //| Fractal Breakout.mq4 | //| tonyc2a@yahoo.com | //| | //| Version 0.9 | //+------------------------------------------------------------------+ /*README This expert determines a price envelope based on the last Up & Down Fractals on whatever time frame the expert is loaded onto. A Buy is triggered when the 'LastUpFractal' is broken and a Sell is triggered when the 'LastDownFractal' is broken. This code is heavily commented and should be easy enough to follow. To filter trades, the expert determines the ATR(5) using the time period of the chart it is loaded onto. If the size of the 'FractalEnvelope' (LastUpFractal minus LastDownFractal) is less than the 'RiskToleranceFactor' times size of the 'FractalEnvelope', then a trade is not entered. By default, the 'RiskToleranceFactor' is set to 2.15. The higher this number, the more trades will be entered, but the lower the 'RiskToleranceFactor' the more likely a trade is to be profitable and the more profitable it is likely to be. I suggest a 'RiskToleranceFactor' of no less than 1.5 and no more than 3. But test this yourself and see what results you come up with. Another filter used by the expert is based on the Daily ATR(3). If the Daily ATR(3) is less than 125 pips an Alert is generated at every tick indicating conditions are not ideal for this strategy. To disable the Alert and trade anyway the user will have to edit the code and comment-out that section of the code. The exit of the trades is determined by nothing more than a Trailing Stop. The 'InitialStop' is set 30 pips away from the entry price. However, in the early stages of profitability of the trade the Trailing Stop is kept tight. At 5 pips profit the Stop is moved to Breakeven. At 10 pips profit the Stop is moved to +5 pips, at 15 pips profit it is moved to +10 pips. When the profit of the trade reaches 20 pips profit the expert then begins using the PSAR as the Stop; if the PSAR is less profitable than the +10 pip Stop the old Stop is used instead. Once the PSAR reaches higher profitability then the last Stop the PSAR becomes the Stop-determining indicator. Default values for the PSAR indicator are 0.07 and 0.2. The user can change these variables without editing the code by changing the 'PSARStepArg' and 'PSARMaxArg'. The expert Alerts the user when a trade has taken place and when there is potential for a trade to take, i.e. when the 'FractalEnvelope' is within RiskToleranceFactor'. When there is potential for a trade, an Alert will be generated with every tick until that potential ceases to exist, so you can be away from your computer and wait for the Alert. The idea is at this point, the user can walk over to his computer disable the Alert, check current condition, see if he really wants to place a trade should the 'FractalEnvelope' be broken, and finally set Stop orders at either end of the 'FractalEnvelope'. The expert currently contains code to place and exit orders, however I would suggest the user manually place orders as well as manage them manually once placed. Also, the expert automatically draws a Fibonacci Retracement between the 'LastUpFractal' and the 'LastDownFractal'. This is a handy tool in and of itself. Finally, the best intraday timeframes to use this expert on are probably the 15M and 30M time frames depending on the user's particular style. 5M is probably acceptable but I would suggest lowering the 'RiskToleranceFactor' to at least a high of 2.00, maybe even lower. On the 1H and 4H charts, more risk is tolerable and profitability is greater, but fewer trades will be signaled. Again, what time frame will depend on the style of the user - do not try to determine what timeframe is most profitable. Use whatever time frame fits your *style* best: many small moves or few large moves. Also take a look at the Daily ATR. During periods of lower Daily ATR you might want to adjust your time frame accordingly. Test it out and see what works best. The Trade Management section, i.e. the section that determines Exits is the weakest logic of the code right now. More work is probably needed even though the current logic works fine. The second weakest section is the Trade Entry code. If you have anything to add to this code please send me an email with your ideas. As far as additional ideas that might be helpful to this strategy, the use of three Open-SMA crosses to confirm entries might also be helpful. It seems that when the 5,8,13 SMAs based on the Open Price are intertwined on the same bar as the breakout occurs, there is more likelihood of profit on a 'FractalEnvelope' Breakout. - tonyc2a@yahoo.com */ #property copyright "tonyc2a@yahoo.com" #property link "" extern double TakeProfit = 50; //should set this to 50 once MQL4 bugs are fixed extern double Lots=1; extern double TrailingStop = 15; extern double InitialStop = 30; extern double PSARStepArg = 0.07; extern double PSARMaxArg = 0.2; extern double RiskToleranceFactor = 2.15; //higher means more risk allowed, set this to 2.15 once bugs fixed extern int slip = 0;//exits only extern double lp = 300; extern double sp = 30; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- TODO: Add your code here. //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- TODO: Add your code here. //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { double b=0; double balance=0; double Ilo=0; balance=AccountBalance(); b=(5*Point+iATR(NULL,0,4,1)*5.5); //---- TODO: Add your code here. //+----Check to see if daily ATR(3) is good for this strategy-----+ // if(iATR(Symbol(),1440,3,0)<125*Point) Alert("The 3 Day ATR for "+Symbol()+" is not ideal for this strategy.\nTo disable this warning edit the code.");//if daily ATR(3) is less than 125 //+---------------------------------------------------------------+ //+----Determines last up and down fractals, and draws fibo retracement between them-+ double LastUpFractal,LastDownFractal,TimeOfLastDownFractal,TimeOfLastUpFractal; double yesterday_high=0; double yesterday_low=0; for(int i=1;i<Bars;i++){//for loop to find last UpFractal if(iFractals(NULL, Period(), MODE_UPPER,i)!=0){// NULL removed Symbol() added LastUpFractal=iFractals(NULL, Period(), MODE_UPPER,i); TimeOfLastUpFractal=Time[i]; break; }//end if }//end for for(int j=1;j<Bars;j++){//for loop to find last DownFractal if(iFractals(NULL, Period(), MODE_LOWER,j)!=0){ LastDownFractal=iFractals(NULL, Period(), MODE_LOWER,j); TimeOfLastDownFractal=Time[j]; break; }//end if }//end for ObjectDelete("Fractal Fibo Retracement"); ObjectCreate("Fractal Fibo Retracement",OBJ_FIBO,0,TimeOfLastUpFractal,LastUpFractal,TimeOfLastDownFractal,LastDownFractal); int FractalEnvelope=MathRound((LastUpFractal-LastDownFractal)/Point); int CurrentATR=MathRound(iATR(Symbol(), Period(),5,0)/Point);//put this value in a int variable so it wouldn't display a bunch of zeros Comment("Fractal Envelope: "+FractalEnvelope+" pips\n", "ATR(5): "+CurrentATR+" pips\n", "BuyStop: "+LastUpFractal+"\n", "SellStop: "+LastDownFractal+"\n", ); //+---------------------------------------------------------------+ //+----Determines if entry conditions have been met---------------+ bool BuyTriggered=false; bool SellTriggered=false; bool FracEnvIsSmallEnough=false; bool FractalIsInsideEnvelope=false; if(FractalEnvelope <= (RiskToleranceFactor * iATR(Symbol(), Period(),5,0)/Point) ){//checks if envelope //is smaller than RiskToleranceFactor times the ATR(5) for the period of the chart FracEnvIsSmallEnough=true; }//end if if(Close[0]<=LastUpFractal && Close[0]>=LastDownFractal){//determines if price is currently inside // FractalEnvelope FractalIsInsideEnvelope=true; }//end if if(FracEnvIsSmallEnough && FractalIsInsideEnvelope){//if envelope is smalle enough and price is inside // envelope, sends an alert to notify user // Alert("FractalEnvelope is "+FractalEnvelope+" pips, and is small enough to indicate trade on the "+Symbol()+" chart."); }//end if if(FracEnvIsSmallEnough){ if(Open[1]<LastUpFractal || Open[1]>LastDownFractal){//checks if the last bar's open was within the // envelope, indicates price is moving out of envelope and not back into it if(Close[0]>LastUpFractal && Close[0]<LastUpFractal+(5*Point) ){//the second condition stops the //alert when the price moves more than 5 pips outside the fractal price BuyTriggered=true; Alert("Buy triggered for "+Symbol()+" on the "+Period()+" minute chart."); }//end if if(Close[0]<LastDownFractal && Close[0]>LastDownFractal-(5*Point) ){//the second condition stops //the alert when the price moves more than 5 pips outside the fractal price SellTriggered=true; Alert("Sell triggered for "+Symbol()+" on the "+Period()+" minute chart."); }//end if }//end if }//end if //+---------------------------------------------------------------+ //+----Enters trade if trigger conditions are met-----------------+ int OrderForThisSymbol=0; for(int x=0;x<OrdersTotal();x++){ OrderSelect(x, SELECT_BY_POS, MODE_TRADES); if(OrderSymbol()==Symbol()) OrderForThisSymbol++; }//end for if(BuyTriggered && OrderForThisSymbol==0){ //Alert("Buy order triggered for "+Symbol()+" on the "+Period()+" minute chart."); int BuyOrderTicket=OrderSend(Symbol(),OP_BUY,Lots,Ask,slip,Ask-(InitialStop*Point),Ask+(TakeProfit*Point),"Buy Order placed at "+CurTime(),0,0,Green); //OP_BUY,Lots,Ask,0,Ask-(InitialStop*Point),Ask+(TakeProfit*Point),"Buy Order placed at "+CurTime(),0,0,Green); //if(BuyOrderTicket==-1) Alert("Buy order failed for some reason."); } if(SellTriggered && OrderForThisSymbol==0){ // Alert("Sell order triggered for "+Symbol()+" on the "+Period()+" minute chart."); int SellOrderTicket=OrderSend(Symbol(),OP_SELL,Lots,Bid,slip,Bid+(InitialStop*Point),Bid-(TakeProfit*Point),"Sell Order placed at "+CurTime(),0,0,Red); //OP_SELL,Lots,Bid,0,Bid+(InitialStop*Point),Bid-(TakeProfit*Point),"Sell Order placed at "+CurTime(),0,0,Red); //if(SellOrderTicket==-1) Alert("Sell order failed for some reason."); } //+---------------------------------------------------------------+ //+----Exits trades based on given criteria, uses PSAR for stop---+ /*if(OrdersTotal()>0){ double CurrentPSAR=iSAR(Symbol(), Period(), PSARStepArg, PSARMaxArg, 0); for(int cnt=0;cnt<OrdersTotal();cnt++){ OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES); double Plus1=OrderOpenPrice()+1*Point; double Plus5=OrderOpenPrice()+5*Point; double Plus10=OrderOpenPrice()+10*Point; if(OrderType()==OP_BUY && OrderSymbol()==Symbol()){ if(OrderProfit()>=6 && OrderProfit()<=10) { OrderModify(OrderTicket(), OrderOpenPrice(), Plus1, OrderTakeProfit(),Green);}//if profit between 6 and 10 move stoploss to breakeven else if(OrderProfit()>=11 && OrderProfit()<=15) { OrderModify(OrderTicket(), OrderOpenPrice(), Plus5, OrderTakeProfit(), Green); }//if profit between 11 and 15 move stoploss to +5 else if(OrderProfit()>=16 && OrderProfit()<=20) { OrderModify(OrderTicket(), OrderOpenPrice(), Plus10, OrderTakeProfit(), Green);}//if profit between 16 and 20 move stoploss to +10 else if(OrderProfit()>=21 && CurrentPSAR>OrderStopLoss()) OrderModify(OrderTicket(),OrderOpenPrice(),CurrentPSAR,OrderTakeProfit(),Green);//if profit greater than 20 move stoploss according to PSAR }//end if if(OrderType()==OP_SELL && OrderSymbol()==Symbol()){ if(OrderProfit()>=5 && OrderProfit()<10) OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-(1*Point),OrderTakeProfit(),Red);//if profit between 5 and 10 move stoploss to breakeven if(OrderProfit()>=10 && OrderProfit()<15) OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-(5*Point),OrderTakeProfit(),Red);//if profit between 10 and 15 move stoploss to +5 if(OrderProfit()>=15 && OrderProfit()<20) OrderModify(OrderTicket(),OrderOpenPrice(),OrderOpenPrice()-(10*Point),OrderTakeProfit(),Red);//if profit between 15 and 20 move stoploss to +10 if(OrderProfit()>=20 && CurrentPSAR>OrderStopLoss()) OrderModify(OrderTicket(),OrderOpenPrice(),CurrentPSAR,OrderTakeProfit(),Red);//if profit greater than 20 move stoploss according to PSAR }//end if }//end for }//end if*/ // ---------------- TRAILING STOP if(TrailingStop>0) { OrderSelect(0, SELECT_BY_POS, MODE_TRADES); if((OrderType() == OP_BUY || OrderType() == OP_BUYSTOP) && (OrderSymbol()==Symbol())) { if(TrailingStop>0) { if(Bid-OrderOpenPrice()>Point*TrailingStop) { if(OrderStopLoss()<Bid-Point*TrailingStop) { OrderModify(OrderTicket(),OrderOpenPrice(),Bid- Point*TrailingStop,OrderTakeProfit(),0,Aqua); return(0); } } } } if((OrderType() == OP_SELL || OrderType() == OP_SELLSTOP) && (OrderSymbol()==Symbol())) { if(TrailingStop>0) { if((OrderOpenPrice()-Ask)>(Point*TrailingStop)) { if(OrderStopLoss()==0.0 || OrderStopLoss()>(Ask+Point*TrailingStop)) { OrderModify(OrderTicket(),OrderOpenPrice (),Ask+Point*TrailingStop,OrderTakeProfit(),0,Aqua); return(0); } } } } } } //+---------------------------------------------------------------+ //Alert("Last Up: "+LastUpFractal+"\nLast Down: "+LastDownFractal); //---- return(0); //+------------------------------------------------------------------+
Sample
Analysis
Market Information Used:
Series array that contains open time of each bar
Series array that contains close prices for each bar
Series array that contains open prices of each bar
Indicator Curves created:
Indicators Used:
Indicator of the average true range
Fractals
Parabolic Stop and Reverse system
Custom Indicators Used:
Order Management characteristics:
Checks for the total of open orders
It automatically opens orders when conditions are reached
It can change open orders parameters, due to possible stepping strategy
Other Features:
It issuies visual alerts to the screen