Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

proper timer coding and syntax

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    proper timer coding and syntax

    hello want to make sure i am doing this correctly

    help would be appreciated




    private void FinalCallTimer()
    {
    if (isFinalCallNoneTimerActive && (DateTime.Now - finalCallNoneStartTime).TotalMinutes >= FinalCallNoneDurationMinutes)
    {
    isFinalCallNoneTimerActive = false; // Deactivate timer after duration
    }

    if (isFinalCallNoneTimerActive)
    {
    finalCall = "NONE"; // Keep final call as NONE if timer is active
    finalCallCount += 1;
    }
    }




    Print("VolumeSpikeIndicator = " + volumeSpikeIndicator.volumeSpikeIsTrue);

    if (volumeSpikeIndicator != null && volumeSpikeIndicator.volumeSpikeIsTrue){
    finalCall = "NONE";
    NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;
    FinalCallTimer();
    Print("Volume Spike Is Active Final Call is NONE");
    return;
    }
    else if (volumeSpikeIndicator.volumeSpikeIsTrue == false){
    Print("No Volume Spike Detected");
    }​

    #2
    Hello thehammer,

    Thank you for your post.

    It's not clear what exactly this code is trying to do, can you provide more details on what you are trying to accomplish?

    If you are creating a timer event, I recommend reviewing the Help Guide page for TriggerCustomEvent().



    Additionally, just as a heads up, our support generally can't answer questions like "does this look right", we would redirect you to try the script and make sure it does what you asked of it. Testing the script is a very important part of the strategy creation process so that squarely falls on the developer to make sure it works as planned.
    Gaby V.NinjaTrader Customer Service

    Comment


      #3
      hello here is more of the code :

      i have a volume spike indicator that tracks a volume spike marks it and alerts when the market move 100 points in the direction of the spike, that suppose to set off a boolean flag for a volume spike alert to be true and the strategy should set a condition to not trade and start a timer for 60 min to keep that condition in place , but it doesn't seem to be working or triggering the timer , so i uploaded a picture of the chart with the volume spike the red lines are where the timer should have started

      your help would be appreciated




      protected override void OnStateChange()
      {
      if (State == State.SetDefaults)
      {
      Description = @"Enter the description for your new custom Strategy here.";
      Name = "API Receiver Call Restructured";
      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;

      API_ConsistentStateDuration = new TimeSpan(0, 0, 15); // default is a mere 15 seconds. User may consider 15 or 30 minutes to be his usable default. Exists in btAddOn
      }
      else if (State == State.Configure)
      {

      }
      else if (State == State.DataLoaded)
      {
      try
      {
      // Instantiate indicators
      vwapIndicator = VWAP();
      volumeSpikeIndicator = VolumeSpikeNT8V3(VolumeSpikePeriod,VolumeThreshold ,100,120,100,100);

      AddChartIndicator(volumeSpikeIndicator);


      // Initialize shared data
      Share("btReceiverV2", "api");
      NinjaTrader.NinjaScript.AddOns.btAddOn.API_Consist entStateDuration = API_ConsistentStateDuration;

      CurrentApiCall = NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g;
      DelayedApiCall = NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin gConfirmed;
      }
      catch (Exception ex)
      {
      Print($"Error during DataLoaded state: {ex.Message}");
      // Consider additional error handling or state management
      }
      }


      }

      protected override void OnBarUpdate()
      {

      // Ensure volumeSpikeIndicator updates on every bar, not just real-time
      if (volumeSpikeIndicator != null)
      {
      // Force indicator to update historically
      volumeSpikeIndicator.Update();
      }

      if (State == State.Realtime)
      {
      NinjaTrader.NinjaScript.AddOns.btAddOn.API_Consist entStateDuration = API_ConsistentStateDuration; // set
      CompareCurrentApiToDelayedApi();
      FinalCallTimer();
      DecideFinalDirectionCall();

      NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;

      Draw.TextFixed(this, "finalCallText", "API Final Call: " + finalCall, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0);
      Draw.TextFixed(this, "isFinalCallNoneTimerActive", "Final Call Active: " + isFinalCallNoneTimerActive, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -30;
      Draw.TextFixed(this, "finalCallCountText", "Final Call Count: " + finalCallCount, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -60;
      Draw.TextFixed(this, "finalCallLastTime", "Last Time Activated: " + finalCallNoneStartTime, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -90;
      }
      }

      private void FinalCallTimer()
      {
      if (isFinalCallNoneTimerActive && (DateTime.Now - finalCallNoneStartTime).TotalMinutes >= FinalCallNoneDurationMinutes)
      {
      isFinalCallNoneTimerActive = false; // Deactivate timer after duration
      }

      if (isFinalCallNoneTimerActive)
      {
      finalCall = "NONE"; // Keep final call as NONE if timer is active
      finalCallCount += 1;
      }
      }



      // Enum for divergence states
      public enum DivergenceState
      {
      Long,
      Short,
      Both,
      None
      }

      private DivergenceState GetDivergenceState(string divergence)
      {
      if (string.IsNullOrEmpty(divergence))
      return DivergenceState.None;

      // Remove square brackets and trim the string
      string trimmedDivergence = divergence.Trim().Trim('[', ']');

      // Logic for LONG divergence
      if (trimmedDivergence == "'Strong Down' 'Strong Up' 'diverged'" ||
      trimmedDivergence == "'Strong Down' 'Weak Up' 'diverged'" ||
      trimmedDivergence == "'Strong Down' 'bullish' 'diverged'" ||
      trimmedDivergence == "'Weak Down' 'Strong Up' 'diverged'" ||
      trimmedDivergence == "'Weak Down' 'Weak Up' 'diverged'" ||
      trimmedDivergence == "'Weak Down' 'bullish' 'diverged'" ||
      trimmedDivergence == "'bearish' 'bullish' 'diverged'" ||
      trimmedDivergence == "'bearish' 'Strong Up' 'diverged'" ||
      trimmedDivergence == "'bearish' 'Weak Up' 'diverged'")
      {
      Print("Divergence going LONG " + divergence);
      return DivergenceState.Long;
      }

      // Logic for SHORT divergence
      else if (trimmedDivergence == "'Strong Up' 'Strong Down' 'diverged'" ||
      trimmedDivergence == "'Strong Up' 'Weak Down' 'diverged'" ||
      trimmedDivergence == "'Strong Up' 'bearish' 'diverged'" ||
      trimmedDivergence == "'Weak Up' 'Strong Down' 'diverged'" ||
      trimmedDivergence == "'Weak Up' 'Weak Down' 'diverged'" ||
      trimmedDivergence == "'Weak Up' 'bearish' 'diverged'" ||
      trimmedDivergence == "'bullish' 'Strong Down' 'diverged'" ||
      trimmedDivergence == "'bullish' 'Weak Down' 'diverged'" ||
      trimmedDivergence == "'bullish' 'bearish' 'diverged'")
      {
      Print("Divergence going SHORT " + divergence);
      return DivergenceState.Short;
      }

      // Logic for BOTH divergence
      else if (trimmedDivergence == "'Strong Up' 'Strong Up' 'aligned'" ||
      trimmedDivergence == "'Strong Up' 'Weak Up' 'aligned'" ||
      trimmedDivergence == "'Strong Up' 'bullish' 'aligned'" ||
      trimmedDivergence == "'bullish' 'Strong Up' 'aligned'" ||
      trimmedDivergence == "'bullish' 'Weak Up' 'aligned'" ||
      trimmedDivergence == "'bullish' 'bullish' 'aligned'" ||
      trimmedDivergence == "'Strong Down' 'Strong Down' 'aligned'" ||
      trimmedDivergence == "'Strong Down' 'Weak Down' 'aligned'" ||
      trimmedDivergence == "'Strong Down' 'bearish' 'aligned'" ||
      trimmedDivergence == "'bearish' 'Strong Down' 'aligned'" ||
      trimmedDivergence == "'bearish' 'Weak Down' 'aligned'" ||
      trimmedDivergence == "'bearish' 'bearish' 'aligned'")
      {
      Print("Divergence going BOTH " + divergence);
      return DivergenceState.Both;
      }

      else
      {
      return DivergenceState.None;
      }
      }

      private string GetChoppinessState(double ci_value)
      {
      if (ci_value >= 61.8)
      {
      return "consolidation ";
      }
      else if (ci_value <= 38.2)
      {
      return " trending ";
      }
      else
      {
      return "neutral ";
      }
      }


      private void DecideFinalDirectionCall()
      {
      DateTime currentTime = Time[0];

      // Initialize variables
      choppiness = NinjaTrader.NinjaScript.Strategies.SuperSignal.cho ppiness;
      string lastApiCall = NinjaTrader.NinjaScript.Strategies.SuperSignal.api Call;
      bool aboveVat = NinjaTrader.NinjaScript.Strategies.SuperSignal.mar ketAboveVat;
      bool belowVab = NinjaTrader.NinjaScript.Strategies.SuperSignal.mar ketBelowVab;
      string superSig = NinjaTrader.NinjaScript.Strategies.SuperSignal.sup erSignalCurrentCall;
      string divergence = NinjaTrader.NinjaScript.Strategies.SuperSignal.div ergence;

      Print("Divergence APIRECIEVER " + divergence);
      Print("SuperSig Api Receiver " + superSig);

      Draw.TextFixed(this, "DivergenceText", "Divergence: " + divergence, TextPosition.TopLeft, Brushes.White, new SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -150;
      Draw.TextFixed(this, "SuperSigText", "SuperSig: " + superSig, TextPosition.TopLeft, Brushes.White, new SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -120;
      Draw.TextFixed(this, "ChoppinessText", "Choppiness: " + choppiness, TextPosition.TopLeft, Brushes.White, new SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -180;

      double choppinessValue;
      if (double.TryParse(NinjaTrader.NinjaScript.Strategie s.SuperSignal.choppiness, out choppinessValue))
      {
      choppinessDouble = choppinessValue;
      }
      else
      {
      Print("Failed to convert choppiness to a double.");
      }

      // Get the choppiness state
      string choppinessState = GetChoppinessState(choppinessDouble);
      Print("Choppiness State: " + choppinessState);

      bool choppienessIsTrend = choppinessState.Contains("trending");
      bool choppienessIsCon = choppinessState.Contains("consolidation");
      bool choppienessIsNeut = choppinessState.Contains("neutral");


      // Ensure that the variables are not null or empty
      if (string.IsNullOrEmpty(superSig) || string.IsNullOrEmpty(divergence) || string.IsNullOrEmpty(lastApiCall))
      {
      Print("SuperSignal, Divergence or ApiCall data is null or empty");
      return;
      }
      Print("VolumeSpikeIndicator = " + volumeSpikeIndicator.volumeSpikeIsTrue);

      if (volumeSpikeIndicator != null && volumeSpikeIndicator.volumeSpikeIsTrue){
      finalCall = "NONE";
      NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;
      FinalCallTimer();
      Print("Volume Spike Is Active Final Call is NONE");
      return;
      }
      else if (volumeSpikeIndicator.volumeSpikeIsTrue == false){
      Print("No Volume Spike Detected");
      }

      Comment


        #4
        Hello,

        I recommend debugging the script using prints so you can determine why your condition isn't evaluating as true as expected.

        If you're going for a timer event, I would also recommend using TriggerCustomEvent. There is a code sample for a simple timer event here:



        Another alternative is to use a simple CurrentBars check to determine when 60 minutes have elapsed. For example, if the strategy is on a 1 minute series and I wanted to check when 60 minutes (60 1-minute bars) have passed from when an event occured:

        Code:
        int mySavedBar;
        
        if (your event conditions)
        mySavedBar = CurrentBar;
        
        if(CurrentBar - mySavedBar >= 60)
        //60 bars have elapsed
        Gaby V.NinjaTrader Customer Service

        Comment


          #5
          hello Gaby , does this look correctly done ,

          Thanks for the help!





          region Using declarations
          using System;
          using System.Collections.Generic;
          using System.ComponentModel;
          using System.ComponentModel.DataAnnotations;
          using System.Linq;
          using System.Text;
          using System.Timers; // Import for Timer
          using System.Threading.Tasks;
          using System.Windows;
          using System.Windows.Input;
          using System.Windows.Media;
          using System.Xml.Serialization;
          using NinjaTrader.Cbi;
          using NinjaTrader.Gui;
          using NinjaTrader.Gui.Chart;
          using NinjaTrader.Gui.SuperDom;
          using NinjaTrader.Gui.Tools;
          using NinjaTrader.Data;
          using NinjaTrader.NinjaScript;
          using NinjaTrader.Core.FloatingPoint;
          using NinjaTrader.NinjaScript.Indicators;
          using NinjaTrader.NinjaScript.DrawingTools;
          using NinjaTrader.NinjaScript.AddOns; // Added for SharedDataStore

          #endregion

          // This namespace holds Strategies in this folder and is required. Do not change it.
          namespace NinjaTrader.NinjaScript.Strategies
          {
          public class APIreceiverCallRestructured : Strategy
          {
          private VWAP vwapIndicator;
          private string CurrentApiCall;
          private string DelayedApiCall;
          private string choppiness;
          //private bool CurrentAndDelayedApiAgree = false;
          public static bool OverrideCurrentAPICall { get; set; }
          private string finalCall;
          private int finalCallCount = 0;
          private Dictionary<int, DateTime> finalCallTimes = new Dictionary<int, DateTime>();
          private int activationCount = 0; // Counter to track dictionary keys
          // Constants for magic numbers
          private VolumeSpikeNT8V3 volumeSpikeIndicator;
          private double choppinessDouble;
          private Timer myTimer; // WPF Dispatcher Timer
          private bool isVolumeSpikeTriggered = false;
          private DateTime timerLastActivated; // Declare the variable to track the last time the timer was activated

          region Parameters
          [NinjaScriptProperty]
          [Display(Name = "Volume Spike Period", Description = "Period for volume spike calculation", Order = 1, GroupName = "Parameters")]
          public int VolumeSpikePeriod { get; set; } = 3;

          [NinjaScriptProperty]
          [Display(Name = "Volume Threshold", Description = "Threshold for volume spike", Order = 2, GroupName = "Parameters")]
          public int VolumeThreshold { get; set; } = 800;

          #endregion


          protected override void OnStateChange()
          {
          if (State == State.SetDefaults)
          {
          Description = @"Enter the description for your new custom Strategy here.";
          Name = "API Receiver Call Restructured";
          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;

          API_ConsistentStateDuration = new TimeSpan(0, 0, 15); // default is a mere 15 seconds. User may consider 15 or 30 minutes to be his usable default. Exists in btAddOn
          }
          else if (State == State.Configure)
          {

          }
          else if (State == State.DataLoaded)
          {
          try
          {
          // Instantiate indicators
          vwapIndicator = VWAP();
          volumeSpikeIndicator = VolumeSpikeNT8V3(VolumeSpikePeriod,VolumeThreshold ,100,120,100,100);

          // Initialize and configure the timer with a 60-minute interval
          myTimer = new Timer(3600000); // 60 minutes in milliseconds
          myTimer.Elapsed += TimerEventProcessor;
          myTimer.AutoReset = false; // Ensure the timer only runs once per start
          myTimer.Enabled = false; // Start disabled; will enable when volume spike occurs


          AddChartIndicator(volumeSpikeIndicator);


          // Initialize shared data
          Share("btReceiverV2", "api");
          NinjaTrader.NinjaScript.AddOns.btAddOn.API_Consist entStateDuration = API_ConsistentStateDuration;

          CurrentApiCall = NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g;
          DelayedApiCall = NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin gConfirmed;
          }
          catch (Exception ex)
          {
          Print($"Error during DataLoaded state: {ex.Message}");
          // Consider additional error handling or state management
          }


          }
          else if (State == State.Terminated)
          {
          // Stop the timer and clean up
          if (myTimer != null)
          {
          myTimer.Enabled = false;
          myTimer.Elapsed -= TimerEventProcessor;
          myTimer = null;
          }
          }


          }

          protected override void OnBarUpdate()
          {

          // Ensure volumeSpikeIndicator updates on every bar, not just real-time
          if (volumeSpikeIndicator != null)
          {
          // Force indicator to update historically
          volumeSpikeIndicator.Update();

          if (volumeSpikeIndicator.volumeSpikeIsTrue)
          {
          isVolumeSpikeTriggered = true;
          TriggerCustomEvent(ProcessVolumeSpike, null);
          }
          }



          if (State == State.Realtime)
          {
          NinjaTrader.NinjaScript.AddOns.btAddOn.API_Consist entStateDuration = API_ConsistentStateDuration; // set
          //CompareCurrentApiToDelayedApi();

          if (!isVolumeSpikeTriggered)
          {
          DecideFinalDirectionCall();
          NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;
          }
          else
          {
          // 'finalCall' remains 'NONE' during the 60 minutes
          // No need to set SharedString here as it's already set to "NONE" in ProcessVolumeSpike()
          }


          //DecideFinalDirectionCall();

          //NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;

          Draw.TextFixed(this, "finalCallText", "API Final Call: " + finalCall, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0);
          Draw.TextFixed(this, "finalCallCountText", "Final Call Count: " + finalCallCount, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -30;


          // Display timer information and volume spike status on the chart
          Draw.TextFixed(this, "VolumeSpikeText", "Volume Spike Active: " + isVolumeSpikeTriggered, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -60;
          Draw.TextFixed(this, "TimerText", "Last Timer Activation: " + timerLastActivated, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -90;
          }
          }

          private void TimerEventProcessor(object sender, ElapsedEventArgs e)
          {
          // Use TriggerCustomEvent to ensure thread safety
          TriggerCustomEvent(state =>
          {
          // Reset finalCall to be determined by normal logic
          isVolumeSpikeTriggered = false; // Reset the flag

          Print("Timer expired. Final Call will now be determined by normal logic.");

          // Stop the timer until the next volume spike
          myTimer.Stop();
          }, null);
          }

          private void ProcessVolumeSpike(object state)
          {
          if (isVolumeSpikeTriggered)
          {
          Print("Volume spike detected! Final Call set to NONE.");
          finalCall = "NONE";
          NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;

          // Start the timer to keep finalCall as "NONE" for 60 minutes
          myTimer.Stop(); // Reset the timer if it's already running
          myTimer.Start();

          // Update the last timer activation time
          timerLastActivated = DateTime.Now;
          }
          }



          // Enum for divergence states
          public enum DivergenceState
          {
          Long,
          Short,
          Both,
          None
          }

          private DivergenceState GetDivergenceState(string divergence)
          {
          if (string.IsNullOrEmpty(divergence))
          return DivergenceState.None;

          // Remove square brackets and trim the string
          string trimmedDivergence = divergence.Trim().Trim('[', ']');

          // Logic for LONG divergence
          if (trimmedDivergence == "'Strong Down' 'Strong Up' 'diverged'" ||
          trimmedDivergence == "'Strong Down' 'Weak Up' 'diverged'" ||
          trimmedDivergence == "'Strong Down' 'bullish' 'diverged'" ||
          trimmedDivergence == "'Weak Down' 'Strong Up' 'diverged'" ||
          trimmedDivergence == "'Weak Down' 'Weak Up' 'diverged'" ||
          trimmedDivergence == "'Weak Down' 'bullish' 'diverged'" ||
          trimmedDivergence == "'bearish' 'bullish' 'diverged'" ||
          trimmedDivergence == "'bearish' 'Strong Up' 'diverged'" ||
          trimmedDivergence == "'bearish' 'Weak Up' 'diverged'")
          {
          Print("Divergence going LONG " + divergence);
          return DivergenceState.Long;
          }

          // Logic for SHORT divergence
          else if (trimmedDivergence == "'Strong Up' 'Strong Down' 'diverged'" ||
          trimmedDivergence == "'Strong Up' 'Weak Down' 'diverged'" ||
          trimmedDivergence == "'Strong Up' 'bearish' 'diverged'" ||
          trimmedDivergence == "'Weak Up' 'Strong Down' 'diverged'" ||
          trimmedDivergence == "'Weak Up' 'Weak Down' 'diverged'" ||
          trimmedDivergence == "'Weak Up' 'bearish' 'diverged'" ||
          trimmedDivergence == "'bullish' 'Strong Down' 'diverged'" ||
          trimmedDivergence == "'bullish' 'Weak Down' 'diverged'" ||
          trimmedDivergence == "'bullish' 'bearish' 'diverged'")
          {
          Print("Divergence going SHORT " + divergence);
          return DivergenceState.Short;
          }

          // Logic for BOTH divergence
          else if (trimmedDivergence == "'Strong Up' 'Strong Up' 'aligned'" ||
          trimmedDivergence == "'Strong Up' 'Weak Up' 'aligned'" ||
          trimmedDivergence == "'Strong Up' 'bullish' 'aligned'" ||
          trimmedDivergence == "'bullish' 'Strong Up' 'aligned'" ||
          trimmedDivergence == "'bullish' 'Weak Up' 'aligned'" ||
          trimmedDivergence == "'bullish' 'bullish' 'aligned'" ||
          trimmedDivergence == "'Strong Down' 'Strong Down' 'aligned'" ||
          trimmedDivergence == "'Strong Down' 'Weak Down' 'aligned'" ||
          trimmedDivergence == "'Strong Down' 'bearish' 'aligned'" ||
          trimmedDivergence == "'bearish' 'Strong Down' 'aligned'" ||
          trimmedDivergence == "'bearish' 'Weak Down' 'aligned'" ||
          trimmedDivergence == "'bearish' 'bearish' 'aligned'")
          {
          Print("Divergence going BOTH " + divergence);
          return DivergenceState.Both;
          }

          else
          {
          return DivergenceState.None;
          }
          }

          private string GetChoppinessState(double ci_value)
          {
          if (ci_value >= 61.8)
          {
          return "consolidation ";
          }
          else if (ci_value <= 38.2)
          {
          return " trending ";
          }
          else
          {
          return "neutral ";
          }
          }


          private void DecideFinalDirectionCall()
          {
          DateTime currentTime = Time[0];

          Last edited by thehammer; 10-31-2024, 08:40 PM.

          Comment


            #6
            Hello thehammer,

            Our support generally can't answer questions like "does this look right", we would encourage you to try the script and make sure it does what you asked of it. Testing the script is a very important part of the strategy creation process so that squarely falls on the developer to make sure it works as planned.

            Gaby V.NinjaTrader Customer Service

            Comment


              #7
              yeah i got it to work , just needed a function to bypass historical activation of the trigger , which i figured out

              Comment


                #8
                hello so i got the volume spike to activate and it switched the mode to none like it was suppose to but the timer did not stay activate , so please help me with what i am doing wrong?



                below is the code sections relating to that



                // This namespace holds Strategies in this folder and is required. Do not change it.
                namespace NinjaTrader.NinjaScript.Strategies
                {
                public class APIreceiverCallBOTH : Strategy
                {
                private VWAP vwapIndicator;
                private string CurrentApiCall;
                private string DelayedApiCall;
                private string choppiness;
                //private bool CurrentAndDelayedApiAgree = false;
                public static bool OverrideCurrentAPICall { get; set; }
                private string finalCall;
                private int finalCallCount = 0;
                private Dictionary<int, DateTime> finalCallTimes = new Dictionary<int, DateTime>();
                private int activationCount = 0; // Counter to track dictionary keys
                // Constants for magic numbers
                private VolumeSpikeNT8V3 volumeSpikeIndicator;
                private double choppinessDouble;
                private Timer myTimer; // WPF Dispatcher Timer
                private bool isVolumeSpikeTriggered = false;
                private DateTime timerLastActivated; // Declare the variable to track the last time the timer was activated

                region Parameters
                [NinjaScriptProperty]
                [Display(Name = "Volume Spike Period", Description = "Period for volume spike calculation", Order = 1, GroupName = "Parameters")]
                public int VolumeSpikePeriod { get; set; } = 3;

                [NinjaScriptProperty]
                [Display(Name = "Volume Threshold", Description = "Threshold for volume spike", Order = 2, GroupName = "Parameters")]
                public int VolumeThreshold { get; set; } = 800;

                #endregion


                protected override void OnStateChange()
                {
                if (State == State.SetDefaults)
                {
                Description = @"Enter the description for your new custom Strategy here.";
                Name = "API Receiver Call BOTH";
                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;

                API_ConsistentStateDuration = new TimeSpan(0, 0, 15); // default is a mere 15 seconds. User may consider 15 or 30 minutes to be his usable default. Exists in btAddOn
                }
                else if (State == State.Configure)
                {

                }
                else if (State == State.DataLoaded)
                {
                try
                {
                // Instantiate indicators
                vwapIndicator = VWAP();
                volumeSpikeIndicator = VolumeSpikeNT8V3(VolumeSpikePeriod,VolumeThreshold ,100,120,100,100);

                // Initialize and configure the timer with a 60-minute interval
                myTimer = new Timer(3600000); // 60 minutes in milliseconds
                myTimer.Elapsed += TimerEventProcessor;
                myTimer.AutoReset = false; // Ensure the timer only runs once per start
                myTimer.Enabled = false; // Start disabled; will enable when volume spike occurs


                AddChartIndicator(volumeSpikeIndicator);


                // Initialize shared data
                Share("btReceiverV2", "api");
                NinjaTrader.NinjaScript.AddOns.btAddOn.API_Consist entStateDuration = API_ConsistentStateDuration;

                CurrentApiCall = NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g;
                DelayedApiCall = NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin gConfirmed;
                }
                catch (Exception ex)
                {
                Print($"Error during DataLoaded state: {ex.Message}");
                // Consider additional error handling or state management
                }


                }
                else if (State == State.Terminated)
                {
                // Stop the timer and clean up
                if (myTimer != null)
                {
                myTimer.Enabled = false;
                myTimer.Elapsed -= TimerEventProcessor;
                myTimer = null;
                }
                }


                }

                protected override void OnBarUpdate()
                {

                // Ensure there are enough bars to perform calculations
                if (CurrentBar > BarsRequiredToTrade)
                {
                // Reset VolumeSpikeIsTrue to false at the start of each bar update
                isVolumeSpikeTriggered = false;

                // Ignore historical data
                if (State != State.Realtime)
                return;

                // Ensure volumeSpikeIndicator updates on every bar, not just real-time
                if (volumeSpikeIndicator != null)
                {
                // Force indicator to update historically
                volumeSpikeIndicator.Update();

                if (volumeSpikeIndicator.volumeSpikeIsTrue)
                {
                isVolumeSpikeTriggered = true;
                TriggerCustomEvent(ProcessVolumeSpike, null);
                }
                }
                }


                if (State == State.Realtime)
                {
                NinjaTrader.NinjaScript.AddOns.btAddOn.API_Consist entStateDuration = API_ConsistentStateDuration; // set

                // Calculate choppienessIsTrend before using it
                choppiness = NinjaTrader.NinjaScript.Strategies.SuperSignal.cho ppiness;

                double choppinessValue;
                if (double.TryParse(choppiness, out choppinessValue))
                {
                choppinessDouble = choppinessValue;
                }
                else
                {
                Print("Failed to convert choppiness to a double.");
                choppinessDouble = 0.0; // default value if parsing fails
                }

                // Get the choppiness state
                string choppinessState = GetChoppinessState(choppinessDouble);
                Print("Choppiness State: " + choppinessState);

                bool choppienessIsTrend = choppinessState.Contains("trending");
                bool choppienessIsCon = choppinessState.Contains("consolidation");
                bool choppienessIsNeut = choppinessState.Contains("neutral");

                if (!isVolumeSpikeTriggered && choppienessIsTrend )
                {
                DecideFinalDirectionCall2();
                NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;
                }
                else
                {
                // 'finalCall' remains 'NONE' during the 60 minutes
                // No need to set SharedString here as it's already set to "NONE" in ProcessVolumeSpike()
                }
                if (!isVolumeSpikeTriggered && !choppienessIsTrend )
                {
                DecideFinalDirectionCall();
                NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;
                }
                else
                {
                // 'finalCall' remains 'NONE' during the 60 minutes
                // No need to set SharedString here as it's already set to "NONE" in ProcessVolumeSpike()
                }


                Draw.TextFixed(this, "finalCallText", "API Final Call: " + finalCall, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0);
                Draw.TextFixed(this, "finalCallCountText", "Final Call Count: " + finalCallCount, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -30;


                // Display timer information and volume spike status on the chart
                Draw.TextFixed(this, "VolumeSpikeText", "Volume Spike Active: " + isVolumeSpikeTriggered, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -60;
                Draw.TextFixed(this, "TimerText", "Last Timer Activation: " + timerLastActivated, TextPosition.TopLeft, Brushes.White, new Gui.Tools.SimpleFont("Arial", 14), Brushes.Transparent, Brushes.Transparent, 0).YPixelOffset = -90;
                }
                }

                private void TimerEventProcessor(object sender, ElapsedEventArgs e)
                {
                // Use TriggerCustomEvent to ensure thread safety
                TriggerCustomEvent(state =>
                {
                // Reset finalCall to be determined by normal logic
                isVolumeSpikeTriggered = false; // Reset the flag

                Print("Timer expired. Final Call will now be determined by normal logic.");

                // Stop the timer until the next volume spike
                myTimer.Stop();
                }, null);
                }

                private void ProcessVolumeSpike(object state)
                {
                if (isVolumeSpikeTriggered)
                {
                Print("Volume spike detected! Final Call set to NONE.");
                finalCall = "NONE";
                NinjaTrader.NinjaScript.AddOns.btAddOn.SharedStrin g = finalCall;

                // Start the timer to keep finalCall as "NONE" for 60 minutes
                myTimer.Stop(); // Reset the timer if it's already running
                myTimer.Start();

                // Update the last timer activation time
                timerLastActivated = DateTime.Now;
                }
                }

                Comment


                  #9
                  Hello,

                  To understand why the script is behaving as it is, it is necessary to add prints to the script that print the values used for the logic of the script to understand how the script is evaluating.

                  In the strategy add prints (outside of any conditions) that print the date time of the bar and all values compared in every condition.

                  The prints should include the time of the bar and should print all values from all variables and all hard coded values in all conditions that must evaluate as true for this action to be triggered. It is very important to include a text label for each value and for each comparison operator in the print to understand what is being compared in the condition sets.

                  The debugging print output should clearly show what the condition is, what time the conditions are being compared, all values being compared, and how they are being compared.

                  Prints will appear in the NinjaScript Output window (New > NinjaScript Output window).

                  I am happy to assist you with analyzing the output from the output window.

                  Run or backtest the script and when the output from the output window appears save this by right-clicking the output window and selecting Save As... -> give the output file a name and save -> then attach the output text file to your reply.

                  Below is a link to a support article that demonstrates using informative prints to understand behavior and includes a link to a video recorded using the Strategy Builder to add prints.

                  https://support.ninjatrader.com/s/ar...nd-TraceOrders
                  Gaby V.NinjaTrader Customer Service

                  Comment


                    #10
                    i figured out what i was doing wrong ,i was resetting the flag on bar update, and i was also not properly using historical state to make sure the spike was not triggering during loading historical data , so i fixed it and it is functioning properly now

                    Comment

                    Latest Posts

                    Collapse

                    Topics Statistics Last Post
                    Started by AgriTrdr, Today, 10:35 AM
                    3 responses
                    23 views
                    0 likes
                    Last Post NinjaTrader_Gaby  
                    Started by kenz987, Today, 12:34 PM
                    2 responses
                    8 views
                    0 likes
                    Last Post kenz987
                    by kenz987
                     
                    Started by ChrisR, Yesterday, 12:04 PM
                    7 responses
                    31 views
                    0 likes
                    Last Post ChrisR
                    by ChrisR
                     
                    Started by markpk1, Today, 11:54 AM
                    5 responses
                    18 views
                    0 likes
                    Last Post NinjaTrader_Erick  
                    Started by sgordet, Today, 07:56 AM
                    1 response
                    21 views
                    0 likes
                    Last Post NinjaTrader_Erick  
                    Working...
                    X