#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
}
}