From f2c01f9bb518dc9fd125934038a52c5750fb84d4 Mon Sep 17 00:00:00 2001 From: moshferatu Date: Fri, 13 Sep 2024 11:34:19 -0700 Subject: [PATCH] Initial commit of 3-Day High / Low strategy --- .../3-day-high-low/ThreeDayHighLowBot.cs | 128 ++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 strategies/3-day-high-low/ThreeDayHighLowBot.cs diff --git a/strategies/3-day-high-low/ThreeDayHighLowBot.cs b/strategies/3-day-high-low/ThreeDayHighLowBot.cs new file mode 100644 index 0000000..2fb35ab --- /dev/null +++ b/strategies/3-day-high-low/ThreeDayHighLowBot.cs @@ -0,0 +1,128 @@ +#region Using declarations +using NinjaTrader.Cbi; +using NinjaTrader.NinjaScript.Indicators; +using System; +using System.ComponentModel.DataAnnotations; +#endregion + +namespace NinjaTrader.NinjaScript.Strategies +{ + public class ThreeDayHighLowBot : Strategy + { + private SMA longTermTrend; + private SMA shortTermTrend; + + protected override void OnStateChange() + { + if (State == State.SetDefaults) + { + Name = "3-Day High / Low Bot"; + Description = @"Taken from chapter 2 of High Probability ETF Trading (2009) by Larry Connors"; + Calculate = Calculate.OnBarClose; + EntriesPerDirection = 2; + IsInstantiatedOnEachOptimizationIteration = false; + + ConsecutiveDays = 3; + LongTermTrendPeriod = 200; + ShortTermTrendPeriod = 5; + EnableLongTrades = true; + EnableShortTrades = true; + EnableAggressiveEntries = false; + } + else if (State == State.DataLoaded) + { + longTermTrend = SMA(LongTermTrendPeriod); + shortTermTrend = SMA(ShortTermTrendPeriod); + } + } + + protected override void OnBarUpdate() + { + if (CurrentBar < Math.Max(LongTermTrendPeriod, ConsecutiveDays + 1)) + return; + + if (EnableLongTrades) + { + if (Close[0] > longTermTrend[0] && Close[0] < shortTermTrend[0]) + { + if (IsConsecutiveLowerHighsAndLows(ConsecutiveDays)) + { + if (Position.MarketPosition == MarketPosition.Flat) + EnterLong(); + else if (Position.MarketPosition == MarketPosition.Long && Close[0] < Position.AveragePrice + && EnableAggressiveEntries) + EnterLong(); + } + } + + if (Position.MarketPosition == MarketPosition.Long && Close[0] > shortTermTrend[0]) + ExitLong(); + } + + if (EnableShortTrades) + { + if (Close[0] < longTermTrend[0] && Close[0] > shortTermTrend[0]) + { + if (IsConsecutiveHigherHighsAndLows(ConsecutiveDays)) + { + if (Position.MarketPosition == MarketPosition.Flat) + EnterShort(); + else if (Position.MarketPosition == MarketPosition.Short && Close[0] > Position.AveragePrice + && EnableAggressiveEntries) + EnterShort(); + } + } + + if (Position.MarketPosition == MarketPosition.Short && Close[0] < shortTermTrend[0]) + ExitShort(); + } + } + + private bool IsConsecutiveLowerHighsAndLows(int days) + { + for (int i = 0; i < days; i++) + { + if (High[i] >= High[i + 1] || Low[i] >= Low[i + 1]) + return false; + } + return true; + } + + private bool IsConsecutiveHigherHighsAndLows(int days) + { + for (int i = 0; i < days; i++) + { + if (High[i] <= High[i + 1] || Low[i] <= Low[i + 1]) + return false; + } + return true; + } + + [NinjaScriptProperty] + [Range(1, int.MaxValue)] + [Display(Name = "Consecutive Days", GroupName = "3-Day High / Low Bot", Order = 1)] + public int ConsecutiveDays { get; set; } + + [NinjaScriptProperty] + [Range(1, int.MaxValue)] + [Display(Name = "Long-Term Trend Period", GroupName = "3-Day High / Low Bot", Order = 2)] + public int LongTermTrendPeriod { get; set; } + + [NinjaScriptProperty] + [Range(1, int.MaxValue)] + [Display(Name = "Short-Term Trend Period", GroupName = "3-Day High / Low Bot", Order = 3)] + public int ShortTermTrendPeriod { get; set; } + + [NinjaScriptProperty] + [Display(Name = "Enable Long Trades", GroupName = "3-Day High / Low Bot", Order = 4)] + public bool EnableLongTrades { get; set; } + + [NinjaScriptProperty] + [Display(Name = "Enable Short Trades", GroupName = "3-Day High / Low Bot", Order = 5)] + public bool EnableShortTrades { get; set; } + + [NinjaScriptProperty] + [Display(Name = "Enable Aggressive Entries", GroupName = "3-Day High / Low Bot", Order = 6)] + public bool EnableAggressiveEntries { get; set; } + } +}