//+------------------------------------------------------------------+ //| WeeklyBreakout.mq4 | //| Andriy Moraru | //| http://www.earnforex.com | //| 2014 | //+------------------------------------------------------------------+ #property copyright "www.EarnForex.com, 2014" #property link "http://www.earnforex.com" #property version "1.01" #property description "Enters long on previous week's High breakout." #property description "Enters short on previous week's Low breakout." #property description "Sets stop-loss on reverse entry." #property description "Normal exit on Monday, when a new week starts." // Money management input double Lots = 0.1; // Basic lot size. input bool MM = false; // MM - If true - ATR-based position sizing. input double Risk = 2; // Risk - Risk tolerance in percentage points. input double FixedBalance = 0; // FixedBalance - If greater than 0, position size calculator will use it instead of actual account balance. input double MoneyRisk = 0; // MoneyRisk - Risk tolerance in base currency. input bool UseMoneyInsteadOfPercentage = false; input bool UseEquityInsteadOfBalance = false; input int LotDigits = 2; // LotDigits - How many digits after dot supported in lot size. For example, 2 for 0.01, 1 for 0.1, 3 for 0.001, etc. // Miscellaneous input string OrderCommentary = "WeeklyBreakout"; input int Slippage = 100; // Tolerated slippage in brokers' pips. input bool ECN_Mode = false; // ECN_Mode: Set to true if stop-loss should be added only after Position Open input int Magic = 132703844; // Global variables // Common ulong LastBars = 0; bool HaveLongPosition; bool HaveShortPosition; double StopLoss; // For MM calculation. double BuySL, SellSL; //+------------------------------------------------------------------+ //| Initialization | //+------------------------------------------------------------------+ int init() { return(0); } //+------------------------------------------------------------------+ //| Deinitialization | //+------------------------------------------------------------------+ int deinit() { return(0); } //+------------------------------------------------------------------+ //| Each tick | //+------------------------------------------------------------------+ int start() { if ((!IsTradeAllowed()) || (IsTradeContextBusy()) || (!IsConnected()) || ((!MarketInfo(Symbol(), MODE_TRADEALLOWED)) && (!IsTesting()))) return(0); if (ECN_Mode) DoSL(); // Trade only if new bar has arrived if (LastBars != Bars) LastBars = Bars; else return(0); GetPositionStates(); if ((HaveShortPosition) || (HaveLongPosition)) ClosePrevious(); RefreshRates(); double StopLevel = MarketInfo(Symbol(), MODE_STOPLEVEL) * Point; double Spread = MarketInfo(Symbol(), MODE_SPREAD) * Point; double UpperEntry = High[1]; double LowerEntry = Low[1]; //Print(UpperEntry, " ", LowerEntry, " ", Ask, " ", Bid); // Set expiration to the end of the current bar. datetime expiration = Time[0] + Period() * 60; BuySL = LowerEntry + Point; // Current price below entry if (UpperEntry - Ask > StopLevel) { // Skip trade if previous week's range was too tight and does not allow setting normal stop-loss. StopLoss = UpperEntry - BuySL; if (StopLoss < (StopLevel + Spread) * Point) return(0); OpenBuyStop(UpperEntry, expiration, BuySL); } else { StopLoss = Bid - BuySL; if (StopLoss < (StopLevel + Spread) * Point) return(0); fBuy(BuySL); } SellSL = UpperEntry - Point; // Current price above entry if (Bid - LowerEntry > StopLevel) { StopLoss = SellSL - LowerEntry; if (StopLoss < (StopLevel + Spread) * Point) return(0); OpenSellStop(LowerEntry, expiration, SellSL); } else { StopLoss = SellSL - Ask; if (StopLoss < (StopLevel + Spread) * Point) return(0); fSell(SellSL); } return(0); } //+------------------------------------------------------------------+ //| Check what position is currently open | //+------------------------------------------------------------------+ void GetPositionStates() { int total = OrdersTotal(); for (int cnt = 0; cnt < total; cnt++) { if (OrderSelect(cnt, SELECT_BY_POS, MODE_TRADES) == false) continue; if (OrderMagicNumber() != Magic) continue; if (OrderSymbol() != Symbol()) continue; if (OrderType() == OP_BUY) { HaveLongPosition = true; HaveShortPosition = false; return; } else if (OrderType() == OP_SELL) { HaveLongPosition = false; HaveShortPosition = true; return; } } HaveLongPosition = false; HaveShortPosition = false; } //+------------------------------------------------------------------+ //| Buy | //+------------------------------------------------------------------+ void fBuy(double SL) { RefreshRates(); if (ECN_Mode) SL = 0; int result = OrderSend(Symbol(), OP_BUY, LotsOptimized(), Ask, Slippage, SL, 0, OrderCommentary, Magic); if (result == -1) { int e = GetLastError(); Print("OrderSend Error: ", e); } } //+------------------------------------------------------------------+ //| Sell | //+------------------------------------------------------------------+ void fSell(double SL) { RefreshRates(); if (ECN_Mode) SL = 0; int result = OrderSend(Symbol(), OP_SELL, LotsOptimized(), Bid, Slippage, SL, 0, OrderCommentary, Magic); if (result == -1) { int e = GetLastError(); Print("OrderSend Error: ", e); } } //+------------------------------------------------------------------+ //| Calculate position size depending on money management parameters.| //+------------------------------------------------------------------+ double LotsOptimized() { if (!MM) return (Lots); double Size, RiskMoney, PositionSize = 0; if (AccountCurrency() == "") return(0); if (FixedBalance > 0) { Size = FixedBalance; } else if (UseEquityInsteadOfBalance) { Size = AccountEquity(); } else { Size = AccountBalance(); } if (!UseMoneyInsteadOfPercentage) RiskMoney = Size * Risk / 100; else RiskMoney = MoneyRisk; double UnitCost = MarketInfo(Symbol(), MODE_TICKVALUE); double TickSize = MarketInfo(Symbol(), MODE_TICKSIZE); if ((StopLoss != 0) && (UnitCost != 0) && (TickSize != 0)) PositionSize = NormalizeDouble(RiskMoney / (StopLoss * UnitCost / TickSize), LotDigits); if (PositionSize < MarketInfo(Symbol(), MODE_MINLOT)) PositionSize = MarketInfo(Symbol(), MODE_MINLOT); else if (PositionSize > MarketInfo(Symbol(), MODE_MAXLOT)) PositionSize = MarketInfo(Symbol(), MODE_MAXLOT); return(PositionSize); } //+------------------------------------------------------------------+ //| Close previous position | //+------------------------------------------------------------------+ void ClosePrevious() { int total = OrdersTotal(); for (int i = 0; i < total; i++) { if (OrderSelect(i, SELECT_BY_POS) == false) continue; if ((OrderSymbol() == Symbol()) && (OrderMagicNumber() == Magic)) { if (OrderType() == OP_BUY) { RefreshRates(); OrderClose(OrderTicket(), OrderLots(), Bid, Slippage); } else if (OrderType() == OP_SELL) { RefreshRates(); OrderClose(OrderTicket(), OrderLots(), Ask, Slippage); } } } } //+------------------------------------------------------------------+ //| Open Buy Stop Pending Order | //+------------------------------------------------------------------+ void OpenBuyStop(double Entry, datetime Expiration, double SL) { for (int i = 0; i < OrdersTotal(); i++) { OrderSelect(i, SELECT_BY_POS); if ((OrderMagicNumber() == Magic) && (OrderType() == ORDER_TYPE_BUY_STOP)) return; } ulong ticket, tries; tries = 0; while (tries < 5) { ticket = OrderSend(Symbol(), ORDER_TYPE_BUY_STOP, LotsOptimized(), Entry, Slippage, SL, 0, OrderCommentary, Magic, Expiration); Print("OpenBuyStop executed. Ticket = " + IntegerToString(ticket) + "."); if (ticket <= 0) { Print("Error occured: " + GetLastError() + ". BuyStop @ " + DoubleToString(Entry, Digits) + "."); tries++; } else tries = 5; } } //+------------------------------------------------------------------+ //| Open Sell Stop Pending Order | //+------------------------------------------------------------------+ void OpenSellStop(double Entry, datetime Expiration, double SL) { for (int i = 0; i < OrdersTotal(); i++) { OrderSelect(i, SELECT_BY_POS); if ((OrderMagicNumber() == Magic) && (OrderType() == ORDER_TYPE_SELL_STOP)) return; } ulong ticket, tries; tries = 0; while (tries < 5) { ticket = OrderSend(Symbol(), ORDER_TYPE_SELL_STOP, LotsOptimized(), Entry, Slippage, SL, 0, OrderCommentary, Magic, Expiration); Print("OpenSellStop executed. Ticket = " + IntegerToString(ticket) + "."); if (ticket <= 0) { Print("Error occured: " + GetLastError() + ". SellStop @ " + DoubleToString(Entry, Digits) + "."); tries++; } else tries = 5; } } //+------------------------------------------------------------------+ //| Applies SL to open positions if ECN mode is on. | //+------------------------------------------------------------------+ void DoSL() { double SL = 0; for (int i = 0; i < OrdersTotal(); i++) { OrderSelect(i, SELECT_BY_POS, MODE_TRADES); if ((OrderMagicNumber() == Magic) && (OrderSymbol() == Symbol())) { if (OrderType() == OP_BUY) { if (StopLoss > 0) SL = BuySL; if ((OrderStopLoss() != SL) && (OrderStopLoss() == 0)) { OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(SL, Digits), 0, 0); } } else if (OrderType() == OP_SELL) { if (StopLoss > 0) SL = SellSL; if ((OrderStopLoss() != SL) && (OrderStopLoss() == 0)) { OrderModify(OrderTicket(), OrderOpenPrice(), NormalizeDouble(SL, Digits), 0, 0); } } } } } //+------------------------------------------------------------------+