From f8f19c6a43ec2ad89151a748ab3993fe2db0328b Mon Sep 17 00:00:00 2001 From: moshferatu Date: Sun, 30 Jun 2024 05:53:18 -0700 Subject: [PATCH] Initial commit of simple mean reversion bot --- strategies/MeanReversionBot.cs | 89 ++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 strategies/MeanReversionBot.cs diff --git a/strategies/MeanReversionBot.cs b/strategies/MeanReversionBot.cs new file mode 100644 index 0000000..f29b04c --- /dev/null +++ b/strategies/MeanReversionBot.cs @@ -0,0 +1,89 @@ +#region Using declarations +using NinjaTrader.Cbi; +using NinjaTrader.NinjaScript.Indicators; +using System.ComponentModel.DataAnnotations; +#endregion + +//This namespace holds Strategies in this folder and is required. Do not change it. +namespace NinjaTrader.NinjaScript.Strategies +{ + public class MeanReversionBot : Strategy + { + private SMA fastMA; + private SMA slowMA; + private StdDev stdDev; + + protected override void OnStateChange() + { + if (State == State.SetDefaults) + { + Description = @"Mean reversion strategy based on standard deviations from a moving average"; + Name = "Mean Reversion 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 = 10; + SlowPeriod = 100; + } + else if (State == State.DataLoaded) + { + fastMA = SMA(FastPeriod); + slowMA = SMA(SlowPeriod); + stdDev = StdDev(FastPeriod); + } + } + + protected override void OnBarUpdate() + { + if (CurrentBar < SlowPeriod) + return; + + double zScore = (Close[0] - fastMA[0]) / stdDev[0]; + + // Exits + if (zScore > -0.5 && zScore < 0.5) + { + if (Position.MarketPosition == MarketPosition.Long) + ExitLong(); + else if (Position.MarketPosition == MarketPosition.Short) + ExitShort(); + } + + if (Position.MarketPosition != MarketPosition.Flat) + return; + + // Entries + if (zScore < -1 && fastMA[0] > slowMA[0]) + EnterLong(); + else if (zScore > 1 && fastMA[0] < slowMA[0]) + EnterShort(); + } + + public override string DisplayName + { + get { return Name; } + } + + [Range(1, int.MaxValue), NinjaScriptProperty] + [Display(Name = "Fast Period", Order = 1, GroupName = "Mean Reversion Bot")] + public int FastPeriod { get; set; } + + [Range(1, int.MaxValue), NinjaScriptProperty] + [Display(Name = "Slow Period", Order = 2, GroupName = "Mean Reversion Bot")] + public int SlowPeriod { get; set; } + } +}