#region Using declarations using System; using System.ComponentModel; using System.Diagnostics; using System.Drawing; using System.Drawing.Drawing2D; using System.Xml.Serialization; using System.Collections.Generic; using NinjaTrader.Cbi; using NinjaTrader.Data; using NinjaTrader.Indicator; using NinjaTrader.Gui.Chart; using NinjaTrader.Strategy; #endregion // This namespace holds all strategies and is required. Do not change it. namespace NinjaTrader.Strategy { /// /// Enter the description of your strategy here /// [Description("Forex D1 SMA5/3 Strategy as presented on ForexFactory.com - http://www.forexfactory.com/showthread.php?t=600112")] public class FX1DSMA5_3 : Strategy { #region Variables // Default settings private int defaultQuantity = 10000; private int currentQuantity = 10000; private int maxQuantity = 1000000; private bool doubleAfterLoss = true; private float defaultTS = 0.005f; private Trade currentTrade = null; private Trade lastTrade = null; private int smaPeriod = 5; private int smaDisplacement = 3; private int bbDeviation = 2; private int bbPeriod = 20; private int conseqWinCount = 0; private int conseqLossCount = 0; private int tradesCounter = 0; private double takeProfitPrice = 0.0f, stopLossPrice = 0.0f; private string shortEntryName = "E Short"; private string shortExitName = "X Short"; private string longEntryName = "E Long"; private string longExitName = "X Long"; #endregion /// /// This method is used to configure the strategy and is called once before any strategy method is called. /// protected override void Initialize() { SMA(smaPeriod).Plots[0].Pen.Color = Color.Firebrick; SMA(smaPeriod).Plots[0].Pen.Width = 1; SMA(smaPeriod).Displacement = smaDisplacement; Add(SMA(smaPeriod)); Add(Bollinger(bbDeviation, bbPeriod)); EntriesPerDirection = 1; ExitOnClose = false; CalculateOnBarClose = true; ClearOutputWindow(); } /// /// Called on each bar update event (incoming tick) /// protected override void OnBarUpdate() { if (Position.MarketPosition == MarketPosition.Flat) { bool bCouldGoShort = false, bCouldGoLong = false; GetMarketPositionOpinion(ref bCouldGoShort, ref bCouldGoLong); if (bCouldGoShort || bCouldGoLong) OpenMarketPosition(bCouldGoShort, bCouldGoLong); } else { AdjustProfitTarget(); } } /// /// Draw trade results on chart /// protected override void OnPositionUpdate(IPosition position) { if (position.MarketPosition == MarketPosition.Long) { double y = Low[1 + smaDisplacement], y2 = Bollinger(bbDeviation, bbPeriod).High[0]; DrawText("Stop", "Stop at " + y.ToString("#.####0") + "----", 0, y, Color.Red); DrawText("Target", "Target at " + y2.ToString("#.####0") + "----", 0, y, Color.Lime); } else if (position.MarketPosition == MarketPosition.Short) { double y = High[1 + smaDisplacement], y2 = Bollinger(bbDeviation, bbPeriod).Low[0]; DrawText("Stop", "Stop at " + y.ToString("#.####0") + "----", 0, y, Color.Red); DrawText("Target", "Target at " + y2.ToString("#.####0") + "----", 0, y, Color.Lime); } else // MarketPosition.Flat { RemoveDrawObject("Stop"); RemoveDrawObject("Target"); int lastTradePosition = 1; lastTrade = Performance.AllTrades[Performance.AllTrades.Count - lastTradePosition]; // Last trade was a winner? if (lastTrade.ProfitCurrency > 0) { currentQuantity = defaultQuantity; conseqLossCount = 0; conseqWinCount++; DrawRectangle("WinnerArea" + CurrentBar, false, BarsSinceEntry(), lastTrade.Entry.Price, -1, lastTrade.Exit.Price, Color.Chartreuse, Color.Chartreuse, 5); Print("Last Trade was a winner!"); } // Last trade was a loser? else if (lastTrade.ProfitCurrency < 0) { conseqWinCount = 0; conseqLossCount++; DrawRectangle("LoserArea" + CurrentBar, false, BarsSinceEntry(), lastTrade.Entry.Price, -1, lastTrade.Exit.Price, Color.Red, Color.Red, 5); if (doubleAfterLoss) { currentQuantity = currentQuantity * 2; if (currentQuantity > maxQuantity) currentQuantity = defaultQuantity; } Print("Last Trade was a loser. New quantity " + currentQuantity); } } } /// /// Opens a market position, depending on what is available /// protected void OpenMarketPosition(bool bCouldGoShort, bool bCouldGoLong) { if (bCouldGoShort && !bCouldGoLong) { openPositionShort(); } else if (bCouldGoLong && !bCouldGoShort) { openPositionLong(); } else if (bCouldGoLong && bCouldGoShort) { Print("OMG SO UNDECIDED!"); } } /// /// Opens a LONG position /// protected void openPositionShort() { double price = Close[0], sl = High[0]; takeProfitPrice = Bollinger(bbDeviation, bbPeriod).Lower[0]; tradesCounter++; Print("[" + tradesCounter + "] SHORT entry on " + Instrument.FullName + " @ " + price.ToString("#.####0") + " / SL: " + sl.ToString("#.####0") + " / TP: " + takeProfitPrice.ToString("#.####0")); DrawLine("TrendLineShort_" + tradesCounter, 2, Low[2], 0, Low[0], Color.Red); DrawText("TrendTextShort_" + tradesCounter, tradesCounter.ToString(), 0, High[0] + 2 * TickSize, Color.Black); DrawPositionChartInfo(MarketPosition.Short, sl, takeProfitPrice); DrawLine("SLLineShort_" + tradesCounter, 2, sl, 0, sl, Color.Red); DrawText("SLTextShort_" + tradesCounter, "SL", 3, sl - 2 * TickSize, Color.Black); DrawLine("TPLineShort_" + tradesCounter, 2, takeProfitPrice, 0, takeProfitPrice, Color.Gold); DrawText("TPTextShort_" + tradesCounter, "TP", 3, takeProfitPrice - 2 * TickSize, Color.Black); EnterShort(currentQuantity, shortEntryName); SetStopLoss(shortEntryName, CalculationMode.Price, sl, false); SetProfitTarget(shortEntryName, CalculationMode.Price, takeProfitPrice); } /// /// Opens a SHORT position /// protected void openPositionLong() { double price = Close[0], sl = Low[0]; takeProfitPrice = Bollinger(bbDeviation, bbPeriod).Upper[0]; tradesCounter++; Print("[" + tradesCounter + "] LONG entry on " + Instrument.FullName + " @ " + price.ToString("#.####0") + " / SL: " + sl.ToString("#.####0") + " / TP: " + takeProfitPrice.ToString("#.####0")); DrawLine("TrendLineLong_" + tradesCounter, 2, Low[2], 0, Low[0], Color.YellowGreen); DrawText("TrendTextLong_" + tradesCounter, tradesCounter.ToString(), 0, Low[0] - 2 * TickSize, Color.Black); DrawPositionChartInfo(MarketPosition.Long, sl, takeProfitPrice); EnterLong(currentQuantity, longEntryName); SetStopLoss(longEntryName, CalculationMode.Price, sl, false); SetProfitTarget(longEntryName, CalculationMode.Price, takeProfitPrice); } /// /// Gets an evaluation of the current market /// protected void GetMarketPositionOpinion(ref bool bCouldGoShort, ref bool bCouldGoLong) { bCouldGoShort = GetMarketPositionOpinionShort(); bCouldGoLong = GetMarketPositionOpinionLong(); } /// /// Checks if the market allows a SHORT position /// protected bool GetMarketPositionOpinionShort() { bool bCouldGoShort = false; double price = GetCurrentBid(), sma1 = SMA(smaPeriod)[0 + smaDisplacement], sma2 = SMA(smaPeriod)[1 + smaDisplacement]; if (price < sma1 && Open[0] > sma2 && Close[0] <= sma2 && High[1] < High[2] ) { bCouldGoShort = true; } return(bCouldGoShort); } /// /// Checks if the market allows a LONG position /// protected bool GetMarketPositionOpinionLong() { bool bCouldGoLong = false; double price = GetCurrentBid(), sma1 = SMA(smaPeriod)[0 + smaDisplacement], sma2 = SMA(smaPeriod)[1 + smaDisplacement]; if (price > sma1 && Open[0] < sma2 && Close[0] >= sma2 && Low[1] < Low[2] ) { bCouldGoLong = true; } return(bCouldGoLong); } /// /// Adjust profit target if market moves in our favor /// protected void AdjustProfitTarget() { if (Position.MarketPosition == MarketPosition.Long) { AdjustProfitTargetLong(); } else if (Position.MarketPosition == MarketPosition.Short) { AdjustProfitTargetShort(); } } /// /// Adjust LONG profit target if market moves in our favor /// protected void AdjustProfitTargetLong() { double pnl = Position.GetProfitLoss(Close[0], PerformanceUnit.Points); if (defaultTS == 0.0f || pnl < defaultTS) return; double sl = Low[3]; SetStopLoss(longEntryName, CalculationMode.Price, sl, false); takeProfitPrice = Bollinger(bbDeviation, bbPeriod).Upper[0] - 5 * TickSize; SetProfitTarget(longEntryName, CalculationMode.Price, takeProfitPrice); DrawPositionChartInfo(MarketPosition.Long, sl, takeProfitPrice); } /// /// Adjust SHORT profit target if market moves in our favor /// protected void AdjustProfitTargetShort() { double pnl = Position.GetProfitLoss(Close[0], PerformanceUnit.Points); if (defaultTS == 0.0f || pnl < defaultTS) return; double sl = High[3]; SetStopLoss(shortEntryName, CalculationMode.Price, sl, false); takeProfitPrice = Bollinger(bbDeviation, bbPeriod).Lower[0] + 5 * TickSize; SetProfitTarget(shortEntryName, CalculationMode.Price, takeProfitPrice); DrawPositionChartInfo(MarketPosition.Short, sl, takeProfitPrice); } /// /// Draw SL and TP position info on chart /// protected void DrawPositionChartInfo(MarketPosition position, double sl, double tp) { if (position == MarketPosition.Short) { RemoveDrawObject("SLLineShort_" + tradesCounter); RemoveDrawObject("SLTextShort_" + tradesCounter); RemoveDrawObject("TPLineShort_" + tradesCounter); RemoveDrawObject("TPTextShort_" + tradesCounter); DrawLine("SLLineShort_" + tradesCounter, 2, sl, 0, sl, Color.Red); DrawText("SLTextShort_" + tradesCounter, "SL", 3, sl - 2 * TickSize, Color.Black); DrawLine("TPLineShort_" + tradesCounter, 2, takeProfitPrice, 0, takeProfitPrice, Color.Gold); DrawText("TPTextShort_" + tradesCounter, "TP", 3, takeProfitPrice - 2 * TickSize, Color.Black); } else if (position == MarketPosition.Long) { RemoveDrawObject("SLLineLong_" + tradesCounter); RemoveDrawObject("SLTextLong_" + tradesCounter); RemoveDrawObject("TPLineLong_" + tradesCounter); RemoveDrawObject("TPTextLong_" + tradesCounter); DrawLine("SLLineLong_" + tradesCounter, 2, sl, 0, sl, Color.Red); DrawText("SLTextLong_" + tradesCounter, "SL", 3, sl - 2 * TickSize, Color.Black); DrawLine("TPLineLong_" + tradesCounter, 2, takeProfitPrice, 0, takeProfitPrice, Color.Gold); DrawText("TPTextLong_" + tradesCounter, "TP", 3, takeProfitPrice - 2 * TickSize, Color.Black); } } #region Properties [Description("Quantity")] [GridCategory("Parameters")] public int Quantity { get { return defaultQuantity; } set { defaultQuantity = Math.Max(1, value); } } [Description("Maximum Quantity")] [GridCategory("Parameters")] public int MaxQuantity { get { return maxQuantity; } set { maxQuantity = Math.Max(1, value); } } [Description("Double Quantity after Loss")] [GridCategory("Parameters")] public bool DoubleQuantityAfterLoss { get { return doubleAfterLoss; } set { doubleAfterLoss = value; } } [Description("Trailing Stop Threshold in Points (0 = disabled)")] [GridCategory("Parameters")] public float TrailingStop { get { return defaultTS; } set { defaultTS = Math.Max(0.0f, value); } } #endregion } }