├── .gitignore ├── images ├── ratios.png ├── controlpanel.png ├── deltachaser.png ├── screenshot.png ├── stackedimbalances.png └── volumesequencing.png ├── AddOns └── OrderFlowBot │ ├── Common │ ├── OrderFlowBotEnums.cs │ ├── OrderFlowBotStrategiesProperties.cs │ ├── OrderFlowBotState.cs │ └── TechnicalLevels.cs │ ├── DataBar │ ├── Dependencies │ │ ├── Prices.cs │ │ ├── Deltas.cs │ │ ├── Ratios.cs │ │ ├── Volumes.cs │ │ └── Imbalances.cs │ ├── OrderFlowBotDataBar.cs │ └── OrderFlowBotDataBars.cs │ ├── Strategies │ ├── StrategyInterface.cs │ ├── StrategiesConfig.cs │ ├── StrategyBase.cs │ ├── Implementations │ │ ├── VolumeSequencing.cs │ │ ├── DeltaChaser.cs │ │ ├── StackedImbalances.cs │ │ └── PivotFader.cs │ └── StrategiesController.cs │ ├── OrderFlowBot.DataBar.cs │ ├── OrderFlowBot.TechnicalLevels.cs │ ├── OrderFlowBot.Debug.cs │ ├── OrderFlowBot.ControlPanel.Strategies.cs │ ├── OrderFlowBot.ControlPanel.TradeManagement.cs │ ├── Indicators │ └── Implementations │ │ └── Ratios.cs │ ├── OrderFlowBot.ControlPanel.cs │ ├── OrderFlowBot.ControlPanel.Direction.cs │ └── OrderFlowBot.cs ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /images/ratios.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marksantiago290/OrderFlowBot-NinjaTrading/HEAD/images/ratios.png -------------------------------------------------------------------------------- /images/controlpanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marksantiago290/OrderFlowBot-NinjaTrading/HEAD/images/controlpanel.png -------------------------------------------------------------------------------- /images/deltachaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marksantiago290/OrderFlowBot-NinjaTrading/HEAD/images/deltachaser.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marksantiago290/OrderFlowBot-NinjaTrading/HEAD/images/screenshot.png -------------------------------------------------------------------------------- /images/stackedimbalances.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marksantiago290/OrderFlowBot-NinjaTrading/HEAD/images/stackedimbalances.png -------------------------------------------------------------------------------- /images/volumesequencing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marksantiago290/OrderFlowBot-NinjaTrading/HEAD/images/volumesequencing.png -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Common/OrderFlowBotEnums.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaTrader.Custom.AddOns 2 | { 3 | public enum BarType 4 | { 5 | Bearish, 6 | Bullish, 7 | Flat 8 | } 9 | 10 | public enum Direction 11 | { 12 | Any, 13 | Flat, 14 | Long, 15 | Short 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/DataBar/Dependencies/Prices.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar.Dependencies 2 | { 3 | public class Prices 4 | { 5 | public double High { get; set; } 6 | public double Low { get; set; } 7 | public double Open { get; set; } 8 | public double Close { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Strategies/StrategyInterface.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.Strategies 2 | { 3 | public interface IStrategyInterface 4 | { 5 | string Name { get; set; } 6 | Direction ValidStrategyDirection { get; set; } 7 | 8 | void CheckStrategy(); 9 | void CheckLong(); 10 | void CheckShort(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/DataBar/Dependencies/Deltas.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar.Dependencies 2 | { 3 | public class Deltas 4 | { 5 | public long Delta { get; set; } 6 | public long MinDelta { get; set; } 7 | public long MaxDelta { get; set; } 8 | public long CumulativeDelta { get; set; } 9 | public double DeltaPercentage { get; set; } 10 | public double MinMaxDeltaRatio { get; set; } 11 | public double MaxMinDeltaRatio { get; set; } 12 | public double DeltaChange { get; set; } 13 | public long DeltaSl { get; set; } 14 | public long DeltaSh { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/OrderFlowBot.DataBar.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar; 2 | 3 | namespace NinjaTrader.NinjaScript.Strategies 4 | { 5 | // Set custom values that needs to access NinjaScript methods since it gives issues when extending elsewhere 6 | public partial class OrderFlowBot : Strategy 7 | { 8 | private OrderFlowDataBarBase GetOrderFlowDataBarBase(int barsAgo) 9 | { 10 | NinjaTrader.NinjaScript.BarsTypes.VolumetricBarsType volumetricBar = Bars.BarsSeries.BarsType as NinjaTrader.NinjaScript.BarsTypes.VolumetricBarsType; 11 | 12 | OrderFlowDataBarBase baseBar = new OrderFlowDataBarBase 13 | { 14 | VolumetricBar = volumetricBar, 15 | BarsAgo = barsAgo, 16 | Time = ToTime(Time[barsAgo]), 17 | CurrentBar = CurrentBar, 18 | High = High[barsAgo], 19 | Low = Low[barsAgo], 20 | Open = Open[barsAgo], 21 | Close = Close[barsAgo], 22 | }; 23 | 24 | return baseBar; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 MARK 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Common/OrderFlowBotStrategiesProperties.cs: -------------------------------------------------------------------------------- 1 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot 2 | { 3 | public struct OrderFlowBotStrategiesPropertiesValues 4 | { 5 | // Delta Chaser 6 | public int DeltaChaserDelta { get; set; } 7 | 8 | // Stacked Imbalances 9 | public bool StackedImbalanceValidOpenTSP { get; set; } 10 | 11 | // Volume Sequencing 12 | public bool VolumeSequencingValidOpenTSP { get; set; } 13 | } 14 | 15 | public static class OrderFlowBotStrategiesProperties 16 | { 17 | // Delta Chaser 18 | public static int DeltaChaserDelta { get; set; } 19 | 20 | // Stacked Imbalances 21 | public static bool StackedImbalanceValidOpenTSP { get; set; } 22 | 23 | // Volume Sequencing 24 | public static bool VolumeSequencingValidOpenTSP { get; set; } 25 | 26 | public static void Initialize(OrderFlowBotStrategiesPropertiesValues config) 27 | { 28 | DeltaChaserDelta = config.DeltaChaserDelta; 29 | StackedImbalanceValidOpenTSP = config.StackedImbalanceValidOpenTSP; 30 | VolumeSequencingValidOpenTSP = config.VolumeSequencingValidOpenTSP; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Common/OrderFlowBotState.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot 4 | { 5 | public class OrderFlowBotState 6 | { 7 | public bool BackTestingEnabled { get; set; } 8 | public string BackTestingStrategyName { get; set; } 9 | public bool AutoTradeEnabled { get; set; } 10 | public Direction SelectedTradeDirection { get; set; } 11 | public Direction ValidStrategyDirection { get; set; } 12 | public string ValidStrategy { get; set; } 13 | public bool DisableTrading { get; set; } 14 | public List SelectedStrategies { get; set; } 15 | public double TriggerStrikePrice { get; set; } 16 | public bool StrikePriceTriggered { get; set; } 17 | 18 | public OrderFlowBotState() 19 | { 20 | BackTestingEnabled = false; 21 | BackTestingStrategyName = ""; 22 | AutoTradeEnabled = false; 23 | SelectedTradeDirection = Direction.Flat; 24 | ValidStrategyDirection = Direction.Flat; 25 | ValidStrategy = "None"; 26 | SelectedStrategies = new List(); 27 | DisableTrading = false; 28 | TriggerStrikePrice = 0; 29 | StrikePriceTriggered = false; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/DataBar/OrderFlowBotDataBar.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.Custom.AddOns; 2 | using NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar.Dependencies; 3 | 4 | namespace NinjaTrader.NinjaScript.AddOns.OrderFlowBot 5 | { 6 | public class OrderFlowBotDataBar 7 | { 8 | public BarType BarType { get; set; } 9 | public int Time { get; set; } 10 | public int BarNumber { get; set; } 11 | 12 | public Prices Prices { get; set; } 13 | public Ratios Ratios { get; set; } 14 | public Volumes Volumes { get; set; } 15 | public Deltas Deltas { get; set; } 16 | public Imbalances Imbalances { get; set; } 17 | 18 | public OrderFlowBotDataBar() 19 | { 20 | Prices = new Prices(); 21 | Ratios = new Ratios(); 22 | Volumes = new Volumes(); 23 | Deltas = new Deltas(); 24 | Imbalances = new Imbalances(); 25 | } 26 | 27 | public void SetBarType() 28 | { 29 | if (this.Prices.Open < this.Prices.Close) 30 | { 31 | this.BarType = BarType.Bullish; 32 | return; 33 | } 34 | 35 | if (this.Prices.Open > this.Prices.Close) 36 | { 37 | this.BarType = BarType.Bearish; 38 | return; 39 | } 40 | 41 | this.BarType = BarType.Flat; 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Strategies/StrategiesConfig.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.Strategies 4 | { 5 | public class StrategiesImplementation 6 | { 7 | // Important. This must match the file name. 8 | public string Name { get; set; } 9 | public string ButtonLabel { get; set; } 10 | } 11 | 12 | public class StrategiesConfig 13 | { 14 | public List StrategiesConfigList { get; set; } 15 | 16 | public StrategiesConfig() 17 | { 18 | // Note that the checks will iterate through the list. Insertion order matters, if you want to prioritize strategy checks. 19 | StrategiesConfigList = new List 20 | { 21 | new StrategiesImplementation 22 | { 23 | Name = "DeltaChaser", 24 | ButtonLabel = "Delta Chaser" 25 | }, 26 | new StrategiesImplementation 27 | { 28 | Name = "StackedImbalances", 29 | ButtonLabel = "Stacked Imbalances" 30 | }, 31 | new StrategiesImplementation 32 | { 33 | Name = "VolumeSequencing", 34 | ButtonLabel = "Volume Sequencing" 35 | } 36 | }; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Common/TechnicalLevels.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot 4 | { 5 | public class PivotPoint 6 | { 7 | public int BarNumber { get; set; } 8 | public double Price { get; set; } 9 | public double Close { get; set; } 10 | public bool IsHigh { get; set; } 11 | public bool DisplayLevel { get; set; } 12 | public bool IsLevelTested { get; set; } 13 | public bool IsLevelBroken { get; set; } 14 | 15 | public PivotPoint(int barNumber, double price, double close, bool isHigh) 16 | { 17 | BarNumber = barNumber; 18 | Price = price; 19 | Close = close; 20 | IsHigh = isHigh; 21 | DisplayLevel = true; 22 | IsLevelTested = false; 23 | IsLevelBroken = false; 24 | } 25 | } 26 | 27 | public class TechnicalLevels 28 | { 29 | public List Pivots; 30 | public PivotPoint CurrentPivot; 31 | public bool IsLookingForHigh; 32 | public bool HasFirstPivot; 33 | public double RequiredTicksForBroken; 34 | 35 | // You can set these in your strategies to print in the main program for debugging. 36 | public double currentLow; 37 | public double previousLow; 38 | public double previousHigh; 39 | public double currentHigh; 40 | 41 | public TechnicalLevels(int currentBar, double requiredTicksForBroken) 42 | { 43 | Pivots = new List(); 44 | CurrentPivot = new PivotPoint(currentBar, 0, 0, false); 45 | IsLookingForHigh = true; 46 | HasFirstPivot = false; 47 | RequiredTicksForBroken = requiredTicksForBroken; 48 | 49 | currentLow = 0; 50 | previousLow = 0; 51 | previousHigh = 0; 52 | currentHigh = 0; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Strategies/StrategyBase.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar; 2 | using System.Collections.Generic; 3 | 4 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.Strategies 5 | { 6 | public abstract class StrategyBase : IStrategyInterface 7 | { 8 | protected readonly OrderFlowBotState orderFlowBotState; 9 | protected readonly OrderFlowBotDataBars dataBars; 10 | protected readonly List technicalLevels; 11 | public abstract string Name { get; set; } 12 | public abstract Direction ValidStrategyDirection { get; set; } 13 | 14 | protected StrategyBase(OrderFlowBotState orderFlowBotState, OrderFlowBotDataBars dataBars, string name, List technicalLevels) 15 | { 16 | this.orderFlowBotState = orderFlowBotState; 17 | this.dataBars = dataBars; 18 | Name = name; 19 | ValidStrategyDirection = Direction.Flat; 20 | this.technicalLevels = technicalLevels; 21 | } 22 | 23 | public virtual void CheckStrategy() 24 | { 25 | if (IsValidLongDirection() && ValidStrategyDirection == Direction.Flat) 26 | { 27 | CheckLong(); 28 | } 29 | 30 | if (IsValidShortDirection() && ValidStrategyDirection == Direction.Flat) 31 | { 32 | CheckShort(); 33 | } 34 | } 35 | 36 | public abstract void CheckLong(); 37 | 38 | public abstract void CheckShort(); 39 | 40 | protected bool IsValidLongDirection() 41 | { 42 | return orderFlowBotState.SelectedTradeDirection == Direction.Long || orderFlowBotState.SelectedTradeDirection == Direction.Any; 43 | } 44 | 45 | protected bool IsValidShortDirection() 46 | { 47 | return orderFlowBotState.SelectedTradeDirection == Direction.Short || orderFlowBotState.SelectedTradeDirection == Direction.Any; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Strategies/Implementations/VolumeSequencing.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar; 2 | using System.Collections.Generic; 3 | 4 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.Strategies 5 | { 6 | public class VolumeSequencing : StrategyBase 7 | { 8 | public override string Name { get; set; } 9 | public override Direction ValidStrategyDirection { get; set; } 10 | 11 | public VolumeSequencing(OrderFlowBotState orderFlowBotState, OrderFlowBotDataBars dataBars, string name, List technicalLevels) 12 | : base(orderFlowBotState, dataBars, name, technicalLevels) 13 | { 14 | } 15 | 16 | public override void CheckStrategy() 17 | { 18 | if (IsValidLongDirection() && ValidStrategyDirection == Direction.Flat) 19 | { 20 | CheckLong(); 21 | } 22 | 23 | if (IsValidShortDirection() && ValidStrategyDirection == Direction.Flat) 24 | { 25 | CheckShort(); 26 | } 27 | } 28 | 29 | public override void CheckLong() 30 | { 31 | if (IsBullishBar() && HasAskVolumeSequencing() && IsOpenAboveTriggerStrikePrice()) 32 | { 33 | ValidStrategyDirection = Direction.Long; 34 | } 35 | } 36 | 37 | public override void CheckShort() 38 | { 39 | if (IsBearishBar() && HasBidVolumeSequencing() && IsOpenBelowTriggerStrikePrice()) 40 | { 41 | ValidStrategyDirection = Direction.Short; 42 | } 43 | } 44 | 45 | private bool IsBullishBar() 46 | { 47 | return dataBars.Bar.BarType == BarType.Bullish; 48 | } 49 | 50 | private bool IsBearishBar() 51 | { 52 | return dataBars.Bar.BarType == BarType.Bearish; 53 | } 54 | 55 | private bool HasAskVolumeSequencing() 56 | { 57 | return dataBars.Bar.Volumes.HasAskVolumeSequencing; 58 | } 59 | 60 | private bool HasBidVolumeSequencing() 61 | { 62 | return dataBars.Bar.Volumes.HasBidVolumeSequencing; 63 | } 64 | 65 | private bool IsOpenAboveTriggerStrikePrice() 66 | { 67 | if (orderFlowBotState.TriggerStrikePrice == 0 || !OrderFlowBotStrategiesProperties.VolumeSequencingValidOpenTSP) 68 | { 69 | return true; 70 | } 71 | 72 | return dataBars.Bar.Prices.Open > orderFlowBotState.TriggerStrikePrice; 73 | } 74 | 75 | private bool IsOpenBelowTriggerStrikePrice() 76 | { 77 | if (orderFlowBotState.TriggerStrikePrice == 0 || !OrderFlowBotStrategiesProperties.VolumeSequencingValidOpenTSP) 78 | { 79 | return true; 80 | } 81 | 82 | return dataBars.Bar.Prices.Open < orderFlowBotState.TriggerStrikePrice; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Strategies/Implementations/DeltaChaser.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar; 2 | using System.Collections.Generic; 3 | 4 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.Strategies 5 | { 6 | // This strategy is designed to chase the move after it exceeds a certain delta. 7 | // Trade the structure with appropriate targets 8 | public class DeltaChaser : StrategyBase 9 | { 10 | public override string Name { get; set; } 11 | public override Direction ValidStrategyDirection { get; set; } 12 | 13 | public DeltaChaser(OrderFlowBotState orderFlowBotState, OrderFlowBotDataBars dataBars, string name, List technicalLevels) 14 | : base(orderFlowBotState, dataBars, name, technicalLevels) 15 | { 16 | } 17 | 18 | public override void CheckStrategy() 19 | { 20 | if (IsValidLongDirection() && ValidStrategyDirection == Direction.Flat) 21 | { 22 | CheckLong(); 23 | } 24 | 25 | if (IsValidShortDirection() && ValidStrategyDirection == Direction.Flat) 26 | { 27 | CheckShort(); 28 | } 29 | } 30 | 31 | public override void CheckLong() 32 | { 33 | if (IsBarType() && IsValidSpotStrikePrice() && IsValidDelta()) 34 | { 35 | ValidStrategyDirection = Direction.Long; 36 | } 37 | } 38 | 39 | public override void CheckShort() 40 | { 41 | if (IsBarType(false) && IsValidSpotStrikePrice(false) && IsValidDelta(false)) 42 | { 43 | ValidStrategyDirection = Direction.Short; 44 | } 45 | } 46 | 47 | private bool IsBarType(bool longCheck = true) 48 | { 49 | if (longCheck) 50 | { 51 | return dataBars.Bar.BarType == BarType.Bullish; 52 | } 53 | 54 | return dataBars.Bar.BarType == BarType.Bearish; 55 | } 56 | 57 | private bool IsValidSpotStrikePrice(bool longCheck = true) 58 | { 59 | if (orderFlowBotState.TriggerStrikePrice == 0) 60 | { 61 | return true; 62 | } 63 | 64 | // Is above trigger strike price 65 | if (longCheck) 66 | { 67 | return dataBars.Bar.Prices.Close > orderFlowBotState.TriggerStrikePrice; 68 | } 69 | 70 | // Is below trigger strike price 71 | return dataBars.Bar.Prices.Close < orderFlowBotState.TriggerStrikePrice; 72 | } 73 | 74 | private bool IsValidDelta(bool longCheck = true) 75 | { 76 | if (longCheck) 77 | { 78 | return dataBars.Bar.Deltas.Delta > OrderFlowBotStrategiesProperties.DeltaChaserDelta; 79 | } 80 | 81 | return dataBars.Bar.Deltas.Delta < OrderFlowBotStrategiesProperties.DeltaChaserDelta; 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Strategies/Implementations/StackedImbalances.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar; 2 | using System.Collections.Generic; 3 | 4 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.Strategies 5 | { 6 | public class StackedImbalances : StrategyBase 7 | { 8 | public override string Name { get; set; } 9 | public override Direction ValidStrategyDirection { get; set; } 10 | 11 | public StackedImbalances(OrderFlowBotState orderFlowBotState, OrderFlowBotDataBars dataBars, string name, List technicalLevels) 12 | : base(orderFlowBotState, dataBars, name, technicalLevels) 13 | { 14 | } 15 | 16 | public override void CheckStrategy() 17 | { 18 | if (IsValidLongDirection() && ValidStrategyDirection == Direction.Flat) 19 | { 20 | CheckLong(); 21 | } 22 | 23 | if (IsValidShortDirection() && ValidStrategyDirection == Direction.Flat) 24 | { 25 | CheckShort(); 26 | } 27 | } 28 | 29 | public override void CheckLong() 30 | { 31 | if (IsBullishBar() && HasValidAskStackedImbalance() && IsOpenAboveTriggerStrikePrice()) 32 | { 33 | ValidStrategyDirection = Direction.Long; 34 | } 35 | } 36 | 37 | public override void CheckShort() 38 | { 39 | if (IsBearishBar() && HasValidBidStackedImbalance() && IsOpenBelowTriggerStrikePrice()) 40 | { 41 | ValidStrategyDirection = Direction.Short; 42 | } 43 | } 44 | 45 | private bool IsBullishBar() 46 | { 47 | return dataBars.Bar.BarType == BarType.Bullish; 48 | } 49 | 50 | private bool IsBearishBar() 51 | { 52 | return dataBars.Bar.BarType == BarType.Bearish; 53 | } 54 | 55 | private bool HasValidAskStackedImbalance() 56 | { 57 | return dataBars.Bar.Imbalances.HasAskStackedImbalances; 58 | } 59 | 60 | private bool HasValidBidStackedImbalance() 61 | { 62 | return dataBars.Bar.Imbalances.HasBidStackedImbalances; 63 | } 64 | 65 | private bool IsOpenAboveTriggerStrikePrice() 66 | { 67 | if (orderFlowBotState.TriggerStrikePrice == 0 || !OrderFlowBotStrategiesProperties.StackedImbalanceValidOpenTSP) 68 | { 69 | return true; 70 | } 71 | 72 | return dataBars.Bar.Prices.Open > orderFlowBotState.TriggerStrikePrice; 73 | } 74 | 75 | private bool IsOpenBelowTriggerStrikePrice() 76 | { 77 | if (orderFlowBotState.TriggerStrikePrice == 0 || !OrderFlowBotStrategiesProperties.StackedImbalanceValidOpenTSP) 78 | { 79 | return true; 80 | } 81 | 82 | return dataBars.Bar.Prices.Open < orderFlowBotState.TriggerStrikePrice; 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/DataBar/Dependencies/Ratios.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.NinjaScript.AddOns.OrderFlowBot; 2 | using System; 3 | using System.Collections.Generic; 4 | 5 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar.Dependencies 6 | { 7 | public class Ratios 8 | { 9 | public double AskRatio { get; set; } 10 | public double BidRatio { get; set; } 11 | public bool HasValidAskExhaustionRatio { get; set; } 12 | public bool HasValidBidExhaustionRatio { get; set; } 13 | public bool HasValidAskAbsorptionRatio { get; set; } 14 | public bool HasValidBidAbsorptionRatio { get; set; } 15 | 16 | public void SetRatios(List bidAskVolumes, bool validBidAskVolumes, BarType dataBarType) 17 | { 18 | if (!validBidAskVolumes) 19 | return; 20 | 21 | double secondBottomBid, bottomBid; 22 | GetBottomBidVolumes(bidAskVolumes, out secondBottomBid, out bottomBid); 23 | BidRatio = CalculateRatio(secondBottomBid, bottomBid); 24 | HasValidBidExhaustionRatio = IsValidExhaustedRatio(BidRatio) && dataBarType == BarType.Bullish; 25 | HasValidBidAbsorptionRatio = IsValidAbsorptionRatio(BidRatio) && dataBarType == BarType.Bullish; 26 | 27 | double topAsk, secondTopAsk; 28 | GetTopAskVolumes(bidAskVolumes, out topAsk, out secondTopAsk); 29 | AskRatio = CalculateRatio(secondTopAsk, topAsk); 30 | HasValidAskExhaustionRatio = IsValidExhaustedRatio(AskRatio) && dataBarType == BarType.Bearish; 31 | HasValidAskAbsorptionRatio = IsValidAbsorptionRatio(AskRatio) && dataBarType == BarType.Bearish; 32 | } 33 | 34 | public void SetLastRatioPrices(List dataBars) 35 | { 36 | double lastBidPrice = 0; 37 | double lastAskPrice = 0; 38 | 39 | for (int i = dataBars.Count - 1; i >= 0; i--) 40 | { 41 | var dataBar = dataBars[i]; 42 | 43 | if ((lastAskPrice == 0) && (dataBar.Ratios.HasValidAskExhaustionRatio || dataBar.Ratios.HasValidAskAbsorptionRatio)) 44 | { 45 | lastAskPrice = dataBar.Prices.High; 46 | } 47 | 48 | if ((lastBidPrice == 0) && (dataBar.Ratios.HasValidBidExhaustionRatio || dataBar.Ratios.HasValidBidAbsorptionRatio)) 49 | { 50 | lastBidPrice = dataBar.Prices.Low; 51 | } 52 | 53 | if (lastBidPrice != 0 && lastAskPrice != 0) 54 | { 55 | break; 56 | } 57 | } 58 | } 59 | 60 | private void GetBottomBidVolumes(List bidAskVolumes, out double secondBottomBid, out double bottomBid) 61 | { 62 | int lastIndex = bidAskVolumes.Count - 1; 63 | secondBottomBid = bidAskVolumes[lastIndex - 1].BidVolume; 64 | bottomBid = bidAskVolumes[lastIndex].BidVolume; 65 | } 66 | 67 | private void GetTopAskVolumes(List bidAskVolumes, out double topAsk, out double secondTopAsk) 68 | { 69 | topAsk = bidAskVolumes[0].AskVolume; 70 | secondTopAsk = bidAskVolumes[1].AskVolume; 71 | } 72 | 73 | private double CalculateRatio(double numerator, double denominator) 74 | { 75 | if (numerator == 0 && denominator == 0) 76 | { 77 | return 0; 78 | } 79 | if (denominator == 0) 80 | { 81 | return Math.Round(numerator, 2); 82 | } 83 | 84 | return Math.Round(numerator / denominator, 2); 85 | } 86 | 87 | private bool IsValidExhaustedRatio(double ratio) 88 | { 89 | return ratio > OrderFlowBotDataBarConfig.ValidExhaustionRatio; 90 | } 91 | 92 | private bool IsValidAbsorptionRatio(double ratio) 93 | { 94 | return ratio < OrderFlowBotDataBarConfig.ValidAbsorptionRatio; 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/DataBar/Dependencies/Volumes.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar.Dependencies 6 | { 7 | public struct BidAskVolume 8 | { 9 | public double Price; 10 | public long BidVolume; 11 | public long AskVolume; 12 | public long Volume; 13 | public long VolumeDelta; 14 | } 15 | 16 | public class Volumes 17 | { 18 | public double PointOfControl { get; set; } 19 | public long Volume { get; set; } 20 | public long BuyingVolume { get; set; } 21 | public long SellingVolume { get; set; } 22 | public List BidAskVolumes { get; set; } 23 | public bool HasBidVolumeSequencing { get; set; } 24 | public bool HasAskVolumeSequencing { get; set; } 25 | public bool HasAskSinglePrint { get; set; } 26 | public bool HasBidSinglePrint { get; set; } 27 | //public double ValueAreaHighPrice { get; set; } 28 | //public double ValueAreaLowPrice { get; set; } 29 | 30 | public Volumes() 31 | { 32 | BidAskVolumes = new List(); 33 | } 34 | 35 | public bool ValidBidAskVolumes() 36 | { 37 | return BidAskVolumes.Count > 2; 38 | } 39 | 40 | public void SetVolumeSequencing(List bidAskVolumes, BarType barType, long totalVolume) 41 | { 42 | if (totalVolume < OrderFlowBotDataBarConfig.ValidVolumeSequencingMinimumVolume || bidAskVolumes.Count < OrderFlowBotDataBarConfig.ValidVolumeSequencing + 1) 43 | { 44 | this.HasAskVolumeSequencing = false; 45 | this.HasBidVolumeSequencing = false; 46 | 47 | return; 48 | } 49 | 50 | int validVolumeSequencing = OrderFlowBotDataBarConfig.ValidVolumeSequencing; 51 | bool isValidSequence = true; 52 | 53 | if (barType == BarType.Bullish) 54 | { 55 | var lastVolumes = bidAskVolumes.Skip(Math.Max(0, bidAskVolumes.Count - validVolumeSequencing)).Take(validVolumeSequencing).Reverse().ToList(); 56 | 57 | // Check if the AskVolume is sequentially increasing 58 | for (int i = 0; i < lastVolumes.Count - 1; i++) 59 | { 60 | if (lastVolumes[i].AskVolume >= lastVolumes[i + 1].AskVolume) 61 | { 62 | isValidSequence = false; 63 | break; 64 | } 65 | } 66 | 67 | this.HasAskVolumeSequencing = isValidSequence; 68 | this.HasBidVolumeSequencing = false; 69 | } 70 | else if (barType == BarType.Bearish) 71 | { 72 | var firstVolumes = bidAskVolumes.Take(validVolumeSequencing).ToList(); 73 | 74 | // Check if the BidVolume is sequentially increasing 75 | for (int i = 0; i < firstVolumes.Count - 1; i++) 76 | { 77 | if (firstVolumes[i].BidVolume >= firstVolumes[i + 1].BidVolume) 78 | { 79 | isValidSequence = false; 80 | break; 81 | } 82 | } 83 | 84 | this.HasAskVolumeSequencing = false; 85 | this.HasBidVolumeSequencing = isValidSequence; 86 | } 87 | else 88 | { 89 | this.HasAskVolumeSequencing = false; 90 | this.HasBidVolumeSequencing = false; 91 | } 92 | } 93 | 94 | public void SetSinglePrints() 95 | { 96 | if (this.BidAskVolumes == null || this.BidAskVolumes.Count == 0) 97 | { 98 | return; 99 | } 100 | 101 | this.HasAskSinglePrint = this.BidAskVolumes.First().AskVolume < 10; 102 | this.HasBidSinglePrint = this.BidAskVolumes.Last().BidVolume < 10; 103 | } 104 | 105 | public void SetBidAskPriceVolumeAndVolumeDelta() 106 | { 107 | if (this.BidAskVolumes == null || this.BidAskVolumes.Count == 0) 108 | { 109 | return; 110 | } 111 | 112 | for (int i = 0; i < this.BidAskVolumes.Count; i++) 113 | { 114 | var bidAskVolume = this.BidAskVolumes[i]; 115 | bidAskVolume.Volume = bidAskVolume.BidVolume + bidAskVolume.AskVolume; 116 | bidAskVolume.VolumeDelta = bidAskVolume.AskVolume - bidAskVolume.BidVolume; 117 | this.BidAskVolumes[i] = bidAskVolume; 118 | } 119 | } 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/OrderFlowBot.TechnicalLevels.cs: -------------------------------------------------------------------------------- 1 | using PivotPoint = NinjaTrader.Custom.AddOns.OrderFlowBot.PivotPoint; 2 | 3 | namespace NinjaTrader.NinjaScript.Strategies 4 | { 5 | public partial class OrderFlowBot : Strategy 6 | { 7 | private void UpdateSupportResistanceLevels(int dataSeries = 0) 8 | { 9 | if (CurrentBars[dataSeries] < BarsRequiredToPlot) return; 10 | 11 | int previousBarNumber = CurrentBars[dataSeries] - 1; 12 | double previousOpen = Opens[dataSeries][1]; 13 | double previousClose = Closes[dataSeries][1]; 14 | double previousHigh = Highs[dataSeries][1]; 15 | double previousLow = Lows[dataSeries][1]; 16 | 17 | if (!_technicalLevels[dataSeries].HasFirstPivot) 18 | { 19 | if (previousOpen <= previousClose) 20 | { 21 | // Set first pivot as low 22 | _technicalLevels[dataSeries].CurrentPivot = new PivotPoint(previousBarNumber, previousLow, previousClose, false); 23 | _technicalLevels[dataSeries].Pivots.Add(_technicalLevels[dataSeries].CurrentPivot); 24 | } 25 | else 26 | { 27 | // Set first pivot as high 28 | _technicalLevels[dataSeries].CurrentPivot = new PivotPoint(previousBarNumber, previousHigh, previousClose, true); 29 | _technicalLevels[dataSeries].Pivots.Add(_technicalLevels[dataSeries].CurrentPivot); 30 | _technicalLevels[dataSeries].IsLookingForHigh = false; 31 | } 32 | 33 | _technicalLevels[dataSeries].HasFirstPivot = true; 34 | return; 35 | } 36 | 37 | // Check level tested 38 | foreach (var pivot in _technicalLevels[dataSeries].Pivots) 39 | { 40 | if (!pivot.DisplayLevel) 41 | { 42 | continue; 43 | } 44 | 45 | // The price is within the threshold and considered as tested 46 | // Check for resistance 47 | if (pivot.IsHigh && previousHigh >= pivot.Price && previousHigh <= pivot.Price + _technicalLevels[dataSeries].RequiredTicksForBroken) 48 | { 49 | pivot.IsLevelTested = true; 50 | } 51 | // Check for support 52 | else if (!pivot.IsHigh && previousLow <= pivot.Price && previousLow >= pivot.Price - _technicalLevels[dataSeries].RequiredTicksForBroken) 53 | { 54 | pivot.IsLevelTested = true; 55 | } 56 | // The price is outside of the threshold and considered as broken 57 | // Check for resistance 58 | else if (pivot.IsHigh && previousHigh > pivot.Price + _technicalLevels[dataSeries].RequiredTicksForBroken) 59 | { 60 | pivot.IsLevelBroken = true; 61 | pivot.DisplayLevel = false; 62 | } 63 | // Check for support 64 | else if (!pivot.IsHigh && previousLow < pivot.Price - _technicalLevels[dataSeries].RequiredTicksForBroken) 65 | { 66 | pivot.IsLevelBroken = true; 67 | pivot.DisplayLevel = false; 68 | } 69 | } 70 | 71 | if (_technicalLevels[dataSeries].IsLookingForHigh) 72 | { 73 | // Update the high pivot until a lower high is found 74 | if (previousHigh > _technicalLevels[dataSeries].CurrentPivot.Price) 75 | { 76 | _technicalLevels[dataSeries].CurrentPivot.BarNumber = previousBarNumber; 77 | _technicalLevels[dataSeries].CurrentPivot.Price = previousHigh; 78 | _technicalLevels[dataSeries].CurrentPivot.Close = previousClose; 79 | } 80 | else if (previousHigh < _technicalLevels[dataSeries].CurrentPivot.Price) 81 | { 82 | // High pivot found and switch to looking for a low pivot 83 | _technicalLevels[dataSeries].Pivots.Add(new PivotPoint(_technicalLevels[dataSeries].CurrentPivot.BarNumber, _technicalLevels[dataSeries].CurrentPivot.Price, _technicalLevels[dataSeries].CurrentPivot.Close, true)); 84 | _technicalLevels[dataSeries].CurrentPivot = new PivotPoint(previousBarNumber, previousLow, previousClose, false); 85 | _technicalLevels[dataSeries].IsLookingForHigh = false; 86 | } 87 | } 88 | else 89 | { 90 | // Update the low pivot until a higher low is found 91 | if (previousLow < _technicalLevels[dataSeries].CurrentPivot.Price) 92 | { 93 | _technicalLevels[dataSeries].CurrentPivot.BarNumber = previousBarNumber; 94 | _technicalLevels[dataSeries].CurrentPivot.Price = previousLow; 95 | _technicalLevels[dataSeries].CurrentPivot.Close = previousClose; 96 | } 97 | else if (previousLow > _technicalLevels[dataSeries].CurrentPivot.Price) 98 | { 99 | // Low pivot found and switch to looking for a high pivot 100 | _technicalLevels[dataSeries].Pivots.Add(new PivotPoint(_technicalLevels[dataSeries].CurrentPivot.BarNumber, _technicalLevels[dataSeries].CurrentPivot.Price, _technicalLevels[dataSeries].CurrentPivot.Close, false)); 101 | _technicalLevels[dataSeries].CurrentPivot = new PivotPoint(previousBarNumber, previousHigh, previousClose, true); 102 | _technicalLevels[dataSeries].IsLookingForHigh = true; 103 | } 104 | } 105 | } 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/OrderFlowBot.Debug.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.NinjaScript.AddOns.OrderFlowBot; 2 | 3 | namespace NinjaTrader.NinjaScript.Strategies 4 | { 5 | // Add to OrderFlowBot directory for debugging or verification 6 | public partial class OrderFlowBot : Strategy 7 | { 8 | public void PrintDataBar(OrderFlowBotDataBar dataBar) 9 | { 10 | 11 | Print(string.Format("{0}", ToDay(Time[0]))); 12 | Print(string.Format("Time: {0}", dataBar.Time)); 13 | Print(string.Format("Bar Number: {0}", dataBar.BarNumber)); 14 | Print(string.Format("Volume: {0}", dataBar.Volumes.Volume)); 15 | 16 | /* 17 | // Technical Levels Example 18 | Print("Count: " + _technicalLevels.Pivots.Count); 19 | Print("Current Looking For High: " + _technicalLevels.IsLookingForHigh); 20 | Print("Current Pivot: "); 21 | Print("BarNumber: " + _technicalLevels.CurrentPivot.BarNumber + ", Price: " + _technicalLevels.CurrentPivot.Price + ", DisplayLevel: " + _technicalLevels.CurrentPivot.DisplayLevel + ", IsHigh: " + _technicalLevels.CurrentPivot.IsHigh); 22 | Print("\n"); 23 | 24 | var lastPivots = _technicalLevels.Pivots.Skip(Math.Max(0, _technicalLevels.Pivots.Count - 6)).Take(6).ToList(); 25 | 26 | foreach (var pivot in lastPivots) 27 | { 28 | Print("BarNumber: " + pivot.BarNumber + ", Price: " + pivot.Price + ", DisplayLevel: " + pivot.DisplayLevel + "IsHigh: " + pivot.IsHigh); 29 | } 30 | 31 | Print("***************"); 32 | Print("\n"); 33 | */ 34 | /* 35 | Print(string.Format("Bid Imbalances: {0}", dataBar.Imbalances.BidImbalances.Count)); 36 | Print(string.Format("Ask Imbalances: {0}", dataBar.Imbalances.AskImbalances.Count)); 37 | Print(string.Format("Bid Stacked Imbalances: {0}", dataBar.Imbalances.BidStackedImbalances.Count)); 38 | Print(string.Format("Ask Stacked Imbalances: {0}", dataBar.Imbalances.AskStackedImbalances.Count)); 39 | 40 | 41 | Print(string.Format("Bar Type: {0}", dataBar.BarType)); 42 | 43 | Print(string.Format("High: {0}", dataBar.Prices.High)); 44 | Print(string.Format("Low: {0}", dataBar.Prices.Low)); 45 | Print(string.Format("Open: {0}", dataBar.Prices.Open)); 46 | Print(string.Format("Close: {0}", dataBar.Prices.Close)); 47 | 48 | 49 | 50 | Print(string.Format("BuyingVolume: {0}", dataBar.Volumes.BuyingVolume)); 51 | Print(string.Format("AskSinglePrint: {0}", dataBar.Volumes.HasAskSinglePrint)); 52 | Print(string.Format("BidSinglePrint: {0}", dataBar.Volumes.HasBidSinglePrint)); 53 | Print(string.Format("SellingVolume: {0}", dataBar.Volumes.SellingVolume)); 54 | Print(string.Format("PointOfControl: {0}", dataBar.Volumes.PointOfControl)); 55 | 56 | Print("Bid/Ask Volume Per Bar:"); 57 | foreach (var kvp in dataBar.Volumes.BidAskVolumes) 58 | { 59 | Print(string.Format("{0} : {1}", kvp.BidVolume, kvp.AskVolume)); 60 | } 61 | 62 | Print(string.Format("Value Area High: {0}", dataBar.Volumes.ValueAreaHighPrice)); 63 | Print(string.Format("Value Area Low: {0}", dataBar.Volumes.ValueAreaLowPrice)); 64 | 65 | Print(string.Format("Bid Ratio: {0}", dataBar.Ratios.BidRatio)); 66 | Print(string.Format("Valid Bid Ratio: {0}", dataBar.Ratios.HasValidBidExhaustionRatio)); 67 | Print(string.Format("Ask Ratio: {0}", dataBar.Ratios.AskRatio)); 68 | Print(string.Format("Valid Ask Ratio: {0}", dataBar.Ratios.HasValidAskExhaustionRatio)); 69 | Print(string.Format("Last Valid Bid Ratio Price: {0}", dataBar.Ratios.LastValidBidRatioPrice)); 70 | Print(string.Format("Last Valid Ask Ratio Price: {0}", dataBar.Ratios.LastValidAskRatioPrice)); 71 | 72 | Print(string.Format("Delta: {0}", dataBar.Deltas.Delta)); 73 | Print(string.Format("Min Delta: {0}", dataBar.Deltas.MinDelta)); 74 | Print(string.Format("Max Delta: {0}", dataBar.Deltas.MaxDelta)); 75 | Print(string.Format("Cumulative Delta: {0}", dataBar.Deltas.CumulativeDelta)); 76 | Print(string.Format("Delta Percentage: {0}", dataBar.Deltas.DeltaPercentage)); 77 | Print(string.Format("MinMax Delta %: {0}", dataBar.Deltas.MinMaxDeltaRatio)); 78 | Print(string.Format("MaxMin Delta %: {0}", dataBar.Deltas.MaxMinDeltaRatio)); 79 | Print(string.Format("Delta Change: {0}", dataBar.Deltas.DeltaChange)); 80 | 81 | 82 | Print("Bid Imbalances"); 83 | Print("["); 84 | foreach (var kvp in dataBar.Imbalances.BidImbalances) 85 | { 86 | Print(string.Format("{0} : {1}", kvp.Price, kvp.Volume)); 87 | } 88 | Print("]"); 89 | Print("Ask Imbalances"); 90 | Print("["); 91 | foreach (var kvp in dataBar.Imbalances.AskImbalances) 92 | { 93 | Print(string.Format("{0} : {1}", kvp.Price, kvp.Volume)); 94 | } 95 | Print("]"); 96 | 97 | Print("Stacked Bid Imbalances"); 98 | Print("["); 99 | foreach (var kvp in dataBar.Imbalances.BidStackedImbalances) 100 | { 101 | Print(string.Format("{0} : {1}", kvp.Price, kvp.Volume)); 102 | } 103 | Print("]"); 104 | Print("Stacked Ask Imbalances"); 105 | Print("["); 106 | foreach (var kvp in dataBar.Imbalances.AskStackedImbalances) 107 | { 108 | Print(string.Format("{0} : {1}", kvp.Price, kvp.Volume)); 109 | } 110 | Print("]"); 111 | 112 | */ 113 | 114 | Print("\n"); 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/Strategies/StrategiesController.cs: -------------------------------------------------------------------------------- 1 | using NinjaTrader.Custom.AddOns.OrderFlowBot.DataBar; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | 6 | namespace NinjaTrader.Custom.AddOns.OrderFlowBot.Strategies 7 | { 8 | public class StrategiesController 9 | { 10 | private readonly OrderFlowBotState _orderFlowBotState; 11 | private readonly OrderFlowBotDataBars _dataBars; 12 | private readonly StrategiesConfig _strategiesConfig; 13 | private readonly List _strategies; 14 | private readonly List _technicalLevels; 15 | 16 | public StrategiesController(OrderFlowBotState orderFlowBotState, OrderFlowBotDataBars dataBars, StrategiesConfig strategiesConfig, List technicalLevels) 17 | { 18 | _orderFlowBotState = orderFlowBotState; 19 | _dataBars = dataBars; 20 | _strategiesConfig = strategiesConfig; 21 | _strategies = new List(); 22 | _technicalLevels = technicalLevels; 23 | 24 | InitializeStrategies(); 25 | 26 | if (_orderFlowBotState.BackTestingEnabled) 27 | { 28 | EnableBackTesting(); 29 | } 30 | _technicalLevels = technicalLevels; 31 | } 32 | 33 | private void InitializeStrategies() 34 | { 35 | // Dynamically creates the strategies based on the name in the config. 36 | foreach (var strategyConfig in _strategiesConfig.StrategiesConfigList) 37 | { 38 | string fullClassName = String.Format("{0}.{1}", this.GetType().Namespace, strategyConfig.Name); 39 | 40 | Type strategyType = Type.GetType(fullClassName); 41 | 42 | if (strategyType != null && typeof(IStrategyInterface).IsAssignableFrom(strategyType)) 43 | { 44 | var strategyInstance = (IStrategyInterface)Activator.CreateInstance(strategyType, _orderFlowBotState, _dataBars, strategyConfig.Name, _technicalLevels); 45 | 46 | if (strategyInstance != null) 47 | { 48 | _strategies.Add(strategyInstance); 49 | } 50 | } 51 | } 52 | } 53 | 54 | public void EnableBackTesting() 55 | { 56 | _orderFlowBotState.SelectedTradeDirection = Direction.Any; 57 | _orderFlowBotState.SelectedStrategies.Add(_orderFlowBotState.BackTestingStrategyName); 58 | } 59 | 60 | public void CheckStrategies() 61 | { 62 | if (_orderFlowBotState.BackTestingEnabled) 63 | { 64 | var backtestingStrategy = _strategies.FirstOrDefault(strategy => strategy.Name == _orderFlowBotState.BackTestingStrategyName); 65 | 66 | if (backtestingStrategy != null) 67 | { 68 | backtestingStrategy.CheckStrategy(); 69 | 70 | if (backtestingStrategy.ValidStrategyDirection != Direction.Flat) 71 | { 72 | _orderFlowBotState.ValidStrategy = backtestingStrategy.Name; 73 | _orderFlowBotState.ValidStrategyDirection = backtestingStrategy.ValidStrategyDirection; 74 | } 75 | } 76 | 77 | return; 78 | } 79 | 80 | // Check only selected strategies 81 | foreach (var strategy in _strategies) 82 | { 83 | if (!_orderFlowBotState.SelectedStrategies.Contains(strategy.Name)) 84 | { 85 | continue; 86 | } 87 | 88 | strategy.CheckStrategy(); 89 | 90 | if (strategy.ValidStrategyDirection != Direction.Flat) 91 | { 92 | _orderFlowBotState.ValidStrategy = strategy.Name; 93 | 94 | // Continue with found valid strategy direction with Trend mode selected 95 | _orderFlowBotState.ValidStrategyDirection = strategy.ValidStrategyDirection; 96 | } 97 | } 98 | } 99 | 100 | public void ResetBackTestingStrategy() 101 | { 102 | _orderFlowBotState.ValidStrategy = "None"; 103 | 104 | var backtestingStrategy = _strategies.FirstOrDefault(strategy => strategy.Name == _orderFlowBotState.BackTestingStrategyName); 105 | 106 | if (backtestingStrategy != null) 107 | { 108 | backtestingStrategy.ValidStrategyDirection = Direction.Flat; 109 | } 110 | } 111 | 112 | // Set all strategies false 113 | public void ResetStrategies() 114 | { 115 | _orderFlowBotState.ValidStrategyDirection = Direction.Flat; 116 | 117 | foreach (var strategy in _strategies) 118 | { 119 | strategy.ValidStrategyDirection = Direction.Flat; 120 | this.RemoveSelectedStrategy(strategy.Name); 121 | } 122 | } 123 | 124 | public void ResetTradeDirection() 125 | { 126 | _orderFlowBotState.SelectedTradeDirection = Direction.Flat; 127 | ResetValidStrategy(); 128 | } 129 | 130 | public void ResetValidStrategy() 131 | { 132 | // Reset valid strategies and direction without removing them 133 | _orderFlowBotState.ValidStrategy = "None"; 134 | _orderFlowBotState.ValidStrategyDirection = Direction.Flat; 135 | 136 | foreach (var strategy in _strategies) 137 | { 138 | strategy.ValidStrategyDirection = Direction.Flat; 139 | } 140 | } 141 | 142 | public void AddSelectedStrategy(string strategy) 143 | { 144 | if (!_orderFlowBotState.SelectedStrategies.Contains(strategy)) 145 | { 146 | _orderFlowBotState.SelectedStrategies.Add(strategy); 147 | } 148 | } 149 | 150 | public void RemoveSelectedStrategy(string strategy) 151 | { 152 | _orderFlowBotState.SelectedStrategies.Remove(strategy); 153 | } 154 | 155 | public bool StrategyExists(string strategy) 156 | { 157 | return _orderFlowBotState.SelectedStrategies.Contains(strategy); 158 | } 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /AddOns/OrderFlowBot/OrderFlowBot.ControlPanel.Strategies.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Windows; 5 | using System.Windows.Controls; 6 | 7 | namespace NinjaTrader.NinjaScript.Strategies 8 | { 9 | public partial class OrderFlowBot : Strategy 10 | { 11 | private Grid _strategiesGrid; 12 | private StackPanel _strategiesPanel; 13 | private Dictionary _strategyButtons; 14 | 15 | private void StrategiesGrid() 16 | { 17 | AddStrategyButtons(); 18 | 19 | _strategiesGrid = new Grid 20 | { 21 | Margin = new Thickness(0, 0, 0, 15), 22 | }; 23 | 24 | _strategiesGrid.ColumnDefinitions.Add(new ColumnDefinition()); 25 | _strategiesGrid.ColumnDefinitions.Add(new ColumnDefinition()); 26 | 27 | int strategyCount = _strategyButtons.Count; 28 | int rows = (int)Math.Ceiling(strategyCount / 2.0); 29 | 30 | // Dynamically add rows based on the number of strategies 31 | for (int j = 0; j < rows; j++) 32 | { 33 | _strategiesGrid.RowDefinitions.Add(new RowDefinition()); 34 | } 35 | 36 | // Add strategy buttons to the grid 37 | int index = 0; 38 | foreach (var buttonInfo in _strategyButtons.Values) 39 | { 40 | int row = index / 2; 41 | int column = index % 2; 42 | 43 | Button strategyButton = CreateButton(buttonInfo.DisplayLabel, buttonInfo.Handler, row, column); 44 | 45 | Grid.SetRow(strategyButton, row); 46 | Grid.SetColumn(strategyButton, column); 47 | 48 | _strategiesGrid.Children.Add(strategyButton); 49 | index++; 50 | } 51 | 52 | TextBlock headerText = GetHeaderText("Strategies"); 53 | 54 | _strategiesPanel = new StackPanel(); 55 | 56 | _strategiesPanel.Children.Add(headerText); 57 | _strategiesPanel.Children.Add(_strategiesGrid); 58 | } 59 | 60 | private void AddStrategyButtons() 61 | { 62 | _strategyButtons = new Dictionary(); 63 | 64 | // Dynamically add buttons for each strategy with event handler 65 | foreach (var strategy in _strategiesConfig.StrategiesConfigList) 66 | { 67 | string buttonLabel = strategy.ButtonLabel; 68 | 69 | if (!string.IsNullOrEmpty(buttonLabel)) 70 | { 71 | _strategyButtons.Add(buttonLabel, new ButtonInfo( 72 | (sender, e) => StrategyButtonClick(buttonLabel, strategy.Name), 73 | false, 74 | buttonLabel, 75 | strategy.Name 76 | )); 77 | } 78 | } 79 | } 80 | 81 | private void UpdateStrategyButtons() 82 | { 83 | foreach (string buttonLabel in _strategyButtons.Keys) 84 | { 85 | string strategyName = _strategyButtons[buttonLabel].Name; 86 | bool isActive = _strategiesController.StrategyExists(strategyName); 87 | string outputMessage = isActive ? String.Format("{0} Enabled", strategyName) : String.Format("{0} Disabled", strategyName); 88 | 89 | SetButtonBackground(_strategiesGrid, _strategyButtons, isActive, buttonLabel); 90 | PrintOutput(outputMessage); 91 | } 92 | } 93 | 94 | private void DisableEnableStrategyButtons() 95 | { 96 | ResetStrategies(); 97 | 98 | foreach (var item in _strategyButtons) 99 | { 100 | Button button = FindChild