From 0909bee23c7d22bafe792c1ad6342295c0981526 Mon Sep 17 00:00:00 2001 From: moshferatu Date: Wed, 7 Aug 2024 06:01:48 -0700 Subject: [PATCH] Add 1st Cross Bot, taken from chapter 24 of Kaufman Constructs Trading Systems --- strategies/FirstCrossBot.cs | 101 ++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 strategies/FirstCrossBot.cs diff --git a/strategies/FirstCrossBot.cs b/strategies/FirstCrossBot.cs new file mode 100644 index 0000000..4124c84 --- /dev/null +++ b/strategies/FirstCrossBot.cs @@ -0,0 +1,101 @@ +#region Using declarations +using NinjaTrader.Cbi; +using NinjaTrader.NinjaScript.Indicators; +using System; +using System.ComponentModel.DataAnnotations; +#endregion + +namespace NinjaTrader.NinjaScript.Strategies +{ + public class FirstCrossBot : Strategy + { + private SMA fastMA; + private SMA slowMA; + private SMA oscillatorMA; + + private Series oscillator; + + protected override void OnStateChange() + { + if (State == State.SetDefaults) + { + Description = @"Taken from chapter 24 of Kaufman Constructs Trading Systems"; + Name = "1st Cross Bot"; + Calculate = Calculate.OnBarClose; + EntriesPerDirection = 1; + EntryHandling = EntryHandling.AllEntries; + IsExitOnSessionCloseStrategy = true; + ExitOnSessionCloseSeconds = 30; + IsFillLimitOnTouch = false; + MaximumBarsLookBack = MaximumBarsLookBack.TwoHundredFiftySix; + OrderFillResolution = OrderFillResolution.Standard; + Slippage = 0; + StartBehavior = StartBehavior.WaitUntilFlat; + TimeInForce = TimeInForce.Gtc; + TraceOrders = false; + RealtimeErrorHandling = RealtimeErrorHandling.StopCancelClose; + StopTargetHandling = StopTargetHandling.PerEntryExecution; + BarsRequiredToTrade = 20; + IsInstantiatedOnEachOptimizationIteration = true; + + FastPeriod = 17; + SlowPeriod = 45; + OscillatorPeriod = 5; + LongOnly = true; + } + else if (State == State.Configure) + { + } + else if (State == State.DataLoaded) + { + fastMA = SMA(FastPeriod); + slowMA = SMA(SlowPeriod); + + oscillator = new Series(this); + oscillatorMA = SMA(oscillator, OscillatorPeriod); + } + } + + protected override void OnBarUpdate() + { + if (CurrentBar < Math.Max(FastPeriod, Math.Max(SlowPeriod, OscillatorPeriod))) + return; + + oscillator[0] = fastMA[0] - slowMA[0]; + + bool isCrossAbove = CrossAbove(oscillator, oscillatorMA, 1); + bool isCrossBelow = CrossBelow(oscillator, oscillatorMA, 1); + + if (isCrossAbove && Low[0] > Low[1]) + EnterLong(); + else if (isCrossBelow && High[0] < High[1] && !LongOnly) + EnterShort(); + + if (Position.MarketPosition == MarketPosition.Long && isCrossBelow) + ExitLong(); + else if (Position.MarketPosition == MarketPosition.Short && isCrossAbove) + ExitShort(); + } + + public override string DisplayName + { + get { return Name; } + } + + [Range(1, int.MaxValue), NinjaScriptProperty] + [Display(Name = "Fast Period", GroupName = "1st Cross Bot", Order = 1)] + public int FastPeriod { get; set; } + + [Range(1, int.MaxValue), NinjaScriptProperty] + [Display(Name = "Slow Period", GroupName = "1st Cross Bot", Order = 2)] + public int SlowPeriod { get; set; } + + [Range(1, int.MaxValue), NinjaScriptProperty] + [Display(Name = "Oscillator Period", GroupName = "1st Cross Bot", Order = 3)] + public int OscillatorPeriod { get; set; } + + [NinjaScriptProperty] + [Display(Name = "Long Only", GroupName = "1st Cross Bot", Order = 4)] + public bool LongOnly { get; set; } + } +}