From d61d7ea08caee8dc8be3ae47a637e737409b96ba Mon Sep 17 00:00:00 2001 From: moshferatu Date: Tue, 18 Jun 2024 04:36:10 -0700 Subject: [PATCH] Simple trend following bot --- strategies/TrendFollowing.cs | 92 ++++++++++++++++++++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 strategies/TrendFollowing.cs diff --git a/strategies/TrendFollowing.cs b/strategies/TrendFollowing.cs new file mode 100644 index 0000000..345baf7 --- /dev/null +++ b/strategies/TrendFollowing.cs @@ -0,0 +1,92 @@ +#region Using declarations +using System; +using System.ComponentModel.DataAnnotations; +using NinjaTrader.Cbi; +using NinjaTrader.NinjaScript.Indicators; +#endregion + +//This namespace holds Strategies in this folder and is required. Do not change it. +namespace NinjaTrader.NinjaScript.Strategies +{ + public class TrendFollowing : Strategy + { + private ATR atr; + private MovingAverage movingAverage; + + protected override void OnStateChange() + { + if (State == State.SetDefaults) + { + Description = @"Determines trend based on moving average slope, takes longs only"; + Name = "Trend Following"; + 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; + + MovingAveragePeriod = 100; + TakeProfit = false; + ATRPeriod = 14; + ATRMultiplier = 2; + } + else if (State == State.DataLoaded) + { + atr = ATR(ATRPeriod); + movingAverage = MovingAverage(MovingAveragePeriod); + } + } + + protected override void OnBarUpdate() + { + if (CurrentBar < Math.Max(MovingAveragePeriod, ATRPeriod)) + return; + + double atrValue = atr[0]; + double profitTarget = ATRMultiplier * atrValue; + + if (movingAverage[0] > movingAverage[1]) + { + EnterLong(); + + if (TakeProfit) + SetProfitTarget(CalculationMode.Ticks, profitTarget / TickSize); + } + else if (movingAverage[0] < movingAverage[1]) + { + ExitLong(); + } + } + + public override string DisplayName + { + get { return Name; } + } + + [Range(1, int.MaxValue), NinjaScriptProperty] + [Display(Name = "Moving Average Period", GroupName = "Trend Following", Order = 1)] + public int MovingAveragePeriod { get; set; } + + [Display(Name = "Take Profit", GroupName = "Trend Following", Order = 2)] + public bool TakeProfit { get; set; } + + [Range(1, int.MaxValue), NinjaScriptProperty] + [Display(Name = "ATR Period", GroupName = "Trend Following", Order = 3)] + public int ATRPeriod { get; set; } + + [Range(0.1, double.MaxValue), NinjaScriptProperty] + [Display(Name = "ATR Multiplier", GroupName = "Trend Following", Order = 4)] + public double ATRMultiplier { get; set; } + } +}