Announcement

Collapse
No announcement yet.

Partner 728x90

Collapse

ChartMarker triggering certain data export to CSV file

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

    ChartMarker triggering certain data export to CSV file

    Hi,

    I just had and idea that possibly could help me journaling trades and I would ask if this is even possible.

    The idea:

    Click image for larger version

Name:	image.png
Views:	187
Size:	38.7 KB
ID:	1326391

    An indicator checks if there is a Symbol Drawn. if yes - then it checks AnchorTime of this Symbol and compares it to the time of certain data plotted of different panel than the chart, and then exports it to the CSV File.
    If above is possible I would love to extend it so that it recognizes which symbol is drawn, and accordingly, it would read and export different data to different excel columns.

    But there are two other questions at start:
    1. How to compare AnchorTime to BarTime. Now I came up with an error: "Argument 1: cannot convert from 'int' to 'System.DateTime'"
    2. How to trigger scaning a chart and export to CSV file manualy, not on BarUpdate. I would like to do it once a day, after market closes. This is an indicator, not a strategy.

    Regards

    #2
    Hello Pabulon,

    What code are you currently trying to use that is resulting in an error? The error is because you are trying to use the wrong variable type for an int.

    To trigger something manually you can use a button, there is an example of creating a button here:

    Comment


      #3
      I've managed to push it to the point when I correctly read time of when DrawingSymbol (in this case Diamond) is drawn.
      But after I try to make so that it also export the closing price of a bar that matches time with the time of the Diamond, then I got this error.
      I have no idea how to solve that

      Code:
      unhandled exception: 'barsAgo' needed to be between 0 and 935 but was 1

      Code:
      #region Using declarations
      using System;
      using System.IO;
      using System.Linq;
      using System.Windows.Controls;
      using NinjaTrader.Cbi;
      using NinjaTrader.Gui.Tools;
      using NinjaTrader.NinjaScript;
      using NinjaTrader.Data;
      using System.Collections.Generic;  // Required for List
      #endregion
      
      namespace NinjaTrader.NinjaScript.Indicators
      {
          public class DiamondScanner : Indicator
          {
              private string filePath;
              private Button exportButton;
      
              protected override void OnStateChange()
              {
                  if (State == State.SetDefaults)
                  {
                      Description = "Scans manually drawn diamonds and exports data to a CSV file.";
                      Name = "DiamondScanner";
                      IsOverlay = true;
                  }
                  else if (State == State.Configure)
                  {
                      // Path to CSV file in the NinjaTrader User Data directory
                      filePath = Path.Combine(NinjaTrader.Core.Globals.UserDataDir, "DiamondData.csv");
                  }
                  else if (State == State.Historical)
                  {
                      // Create the export button for CSV
                      Dispatcher.InvokeAsync(() =>
                      {
                          exportButton = new Button
                          {
                              Content = "Export Diamonds to CSV",
                              HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
                              VerticalAlignment = System.Windows.VerticalAlignment.Top
                          };
      
                          // Assign method to handle button click
                          exportButton.Click += ExportButton_Click;
      
                          // Add the button to the chart
                          ChartControl.Dispatcher.InvokeAsync(() =>
                          {
                              var parentControl = (System.Windows.Controls.Panel)ChartControl.Parent;
                              parentControl.Children.Add(exportButton);
                          });
                      });
                  }
              }
      
              private void ExportButton_Click(object sender, System.Windows.RoutedEventArgs e)
              {
                  var exportData = new List<string>();
      
                  foreach (var drawObject in DrawObjects)
                  {
                      if (drawObject is NinjaTrader.NinjaScript.DrawingTools.Diamond diamond)
                      {
                          if (diamond.Tag != null && diamond.Tag.StartsWith("Diamond", StringComparison.OrdinalIgnoreCase))
                          {
                              double closingPrice = GetClosingPriceAtAnchorTime(diamond.Anchor.Time);
      
                              // Export if a valid price was found
                              if (closingPrice > 0)
                              {
                                  string timeFormatted = diamond.Anchor.Time.ToString("yyyy-MM-dd HH:mm:ss");
                                  exportData.Add($"{timeFormatted},{closingPrice}");
                              }
                          }
                      }
                  }
      
                  if (exportData.Any())
                  {
                      SaveToCSV(exportData);
                  }
              }
      
      private double GetClosingPriceAtAnchorTime(DateTime anchorTime)
      {
          // Get the date of the most recent bar
          DateTime lastBarDate = Time[0].Date;
      
          // Iterate over bars within the valid range
          for (int i = 0; i < Bars.Count; i++)
          {
              if (i >= Count) // Ensure we do not exceed the available bars
                  break;
      
              DateTime barTime = Time[i];
      
              // Check if the bar is from the same date and time as the diamond's AnchorTime
              if (barTime.Date == lastBarDate && barTime == anchorTime)
              {
                  return Closes[0][i]; // Return the closing price
              }
          }
      
          // Return 0 if no matching bar is found
          return 0;
      }
      
      
              private void SaveToCSV(List<string> exportData)
              {
                  try
                  {
                      if (!File.Exists(filePath))
                      {
                          using (StreamWriter sw = new StreamWriter(filePath, false))
                          {
                              sw.WriteLine("Time,ClosingPrice");
                          }
                      }
      
                      using (StreamWriter sw = new StreamWriter(filePath, true))
                      {
                          foreach (var line in exportData)
                          {
                              sw.WriteLine(line);
                          }
                      }
      
                      Print("Export completed successfully.");
                  }
                  catch (Exception ex)
                  {
                      Print($"Error writing to CSV file: {ex.Message}");
                  }
              }
          }
      }​

      Here is the most recent - error free version.

      Code:
      #region Using declarations
      using System;
      using System.IO;
      using System.Linq;
      using System.Windows.Controls;
      using NinjaTrader.Cbi;
      using NinjaTrader.Gui.Tools;
      using NinjaTrader.NinjaScript;
      using NinjaTrader.Data;
      using System.Collections.Generic;  // Required for List
      #endregion
      
      namespace NinjaTrader.NinjaScript.Indicators
      {
          public class DiamondScanner : Indicator
          {
              private string filePath;
              private bool exportTriggered = false;
              private Button exportButton;
      
              protected override void OnStateChange()
              {
                  if (State == State.SetDefaults)
                  {
                      Description = "Scans manually drawn diamonds and exports data to a CSV file.";
                      Name = "DiamondScanner";
                      IsOverlay = true;
                  }
                  else if (State == State.Configure)
                  {
                      // Path to CSV file in the NinjaTrader User Data directory
                      filePath = Path.Combine(NinjaTrader.Core.Globals.UserDataDir, "DiamondData.csv");
                  }
                  else if (State == State.Historical)
                  {
                      // Create the export button for CSV
                      Dispatcher.InvokeAsync(() =>
                      {
                          exportButton = new Button
                          {
                              Content = "Export Diamonds to CSV",
                              HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
                              VerticalAlignment = System.Windows.VerticalAlignment.Top
                          };
      
                          // Assign method to handle button click
                          exportButton.Click += ExportButton_Click;
      
                          // Add the button to the chart
                          ChartControl.Dispatcher.InvokeAsync(() =>
                          {
                              // Using Parent (the container of chart) to add the button
                              var parentControl = (System.Windows.Controls.Panel)ChartControl.Parent;
                              parentControl.Children.Add(exportButton);
                          });
                      });
                  }
              }
      
              private void ExportButton_Click(object sender, System.Windows.RoutedEventArgs e)
              {
                  // Create a list to store the data before exporting to CSV
                  var exportData = new List<string>();
      
                  foreach (var drawObject in DrawObjects)
                  {
                      if (drawObject is NinjaTrader.NinjaScript.DrawingTools.Diamond diamond)
                      {
                          // Check if the tag contains "Diamond"
                          if (diamond.Tag != null && diamond.Tag.StartsWith("Diamond", StringComparison.OrdinalIgnoreCase))
                          {
                              // Get the time in HHmm format and the closing price
                              int diamondTime = diamond.Anchor.Time.Hour * 100 + diamond.Anchor.Time.Minute;
      
                              // Check the corresponding bar within the last 104 bars
                              double closingPrice = GetClosingPriceAtDiamondTime(diamond.Anchor.Time);
      
                              // Prepare the data for CSV export
                              string line = $"{diamondTime},{closingPrice}";
                              exportData.Add(line);
                          }
                      }
                  }
      
                  // If we have data to export, proceed with saving to CSV
                  if (exportData.Any())
                  {
                      SaveToCSV(exportData);
                  }
              }
      
              private double GetClosingPriceAtDiamondTime(DateTime diamondTime)
              {
                  // Get the last bar time (most recent bar)
                  DateTime lastBarTime = Time[0];  // Time[0] is the time of the most recent bar
      
                  // Compare only the date part of the last bar and the diamond time
                  if (diamondTime.Date != lastBarTime.Date)
                  {
                      return 0;  // If the dates are different, return 0 (no match)
                  }
      
                  // If the dates are the same, check the bars from the same day
                  for (int i = Bars.Count - 1; i >= 0; i--)
                  {
                      DateTime barTime = Time[i];
      
                      // If the bar is from the same day, compare hour and minute
                      if (diamondTime.Date == barTime.Date && diamondTime.Hour == barTime.Hour && diamondTime.Minute == barTime.Minute)
                      {
                          // Return the closing price if a match is found
                          return Closes[0][i];
                      }
                  }
      
                  // Return 0 if no matching bar is found
                  return 0;
              }
      
              private void SaveToCSV(List<string> exportData)
              {
                  try
                  {
                      // Create the file if it doesn't exist
                      if (!File.Exists(filePath))
                      {
                          using (StreamWriter sw = new StreamWriter(filePath, false))
                          {
                              sw.WriteLine("Time,ClosingPrice");
                          }
                      }
      
                      // Append the export data to the CSV file
                      using (StreamWriter sw = new StreamWriter(filePath, true))
                      {
                          foreach (var line in exportData)
                          {
                              sw.WriteLine(line);
                          }
                      }
                  }
                  catch (Exception ex)
                  {
                      Print($"Error writing to CSV file: {ex.Message}");
                  }
              }
          }
      }​
      I got a feeling that after solving this, it will be only easier, please help.
      Last edited by Pabulon; 12-02-2024, 06:43 PM.

      Comment


        #4
        Here is another take, this time using bar indexing. And the same error...

        Code:
        #region Using declarations
        using System;
        using System.IO;
        using System.Linq;
        using System.Windows.Controls;
        using NinjaTrader.Cbi;
        using NinjaTrader.Gui.Tools;
        using NinjaTrader.NinjaScript;
        using NinjaTrader.Data;
        using System.Collections.Generic;  // Required for List
        #endregion
        
        namespace NinjaTrader.NinjaScript.Indicators
        {
            public class DiamondScanner : Indicator
            {
                private string filePath;
                private Button exportButton;
        
                protected override void OnStateChange()
                {
                    if (State == State.SetDefaults)
                    {
                        Description = "Scans manually drawn diamonds and exports data to a CSV file.";
                        Name = "DiamondScanner";
                        IsOverlay = true;
                    }
                    else if (State == State.Configure)
                    {
                        // Path to CSV file in the NinjaTrader User Data directory
                        filePath = Path.Combine(NinjaTrader.Core.Globals.UserDataDir, "DiamondData.csv");
                    }
                    else if (State == State.Historical)
                    {
                        // Create the export button for CSV
                        Dispatcher.InvokeAsync(() =>
                        {
                            exportButton = new Button
                            {
                                Content = "Export Diamonds to CSV",
                                HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
                                VerticalAlignment = System.Windows.VerticalAlignment.Top
                            };
        
                            // Assign method to handle button click
                            exportButton.Click += ExportButton_Click;
        
                            // Add the button to the chart
                            ChartControl.Dispatcher.InvokeAsync(() =>
                            {
                                var parentControl = (System.Windows.Controls.Panel)ChartControl.Parent;
                                parentControl.Children.Add(exportButton);
                            });
                        });
                    }
                }
        
                private void ExportButton_Click(object sender, System.Windows.RoutedEventArgs e)
                {
                    // Create a list to store the data before exporting to CSV
                    var exportData = new List<string>();
        
                    foreach (var drawObject in DrawObjects)
                    {
                        if (drawObject is NinjaTrader.NinjaScript.DrawingTools.Diamond diamond)
                        {
                            // Check if the tag contains "Diamond"
                            if (diamond.Tag != null && diamond.Tag.StartsWith("Diamond", StringComparison.OrdinalIgnoreCase))
                            {
                                // Get the time and closing price for the diamond
                                DateTime diamondTime = diamond.Anchor.Time;
                                double closingPrice = GetClosingPriceAtDiamondTime(diamondTime);
        
                                // Prepare the data for CSV export with formatted closing price
                                string line = $"{diamondTime:yyyy-MM-dd HH:mm:ss},{closingPrice:F2}";
                                exportData.Add(line);
                            }
                        }
                    }
        
                    // If we have data to export, proceed with saving to CSV
                    if (exportData.Any())
                    {
                        SaveToCSV(exportData);
                    }
                }
        
        private double GetClosingPriceAtDiamondTime(DateTime diamondTime)
        {
         
            int barIndex = FindBarIndexByTime(diamondTime);
        
          
            if (barIndex >= 0 && barIndex < Bars.Count)
            {
                return Closes[0][barIndex]; // Zwróć cenę zamknięcia
            }
        
            return 0;
        }
        
        
        private int FindBarIndexByTime(DateTime time)
        {
          
            if (time < Time[Bars.Count - 1] || time > Time[0])
            {
                return -1; // Zwróć -1, jeśli czas nie znajduje się w zakresie
            }
        
        
            for (int i = 0; i < Bars.Count; i++)
            {
                // Porównaj czas świecy z podanym czasem
                if (Time[i] == time)
                {
                    return i;
                }
            }
        
            return -1;
        }
        
        
                private void SaveToCSV(List<string> exportData)
                {
                    try
                    {
                        // Create the file if it doesn't exist
                        if (!File.Exists(filePath))
                        {
                            using (StreamWriter sw = new StreamWriter(filePath, false))
                            {
                                sw.WriteLine("Time,ClosingPrice");
                            }
                        }
        
                        // Append the export data to the CSV file
                        using (StreamWriter sw = new StreamWriter(filePath, true))
                        {
                            foreach (var line in exportData)
                            {
                                sw.WriteLine(line);
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Print($"Error writing to CSV file: {ex.Message}");
                    }
                }
            }
        }​



        Another iteration - still the same issue !@%$!#%@#

        Code:
        #region Using declarations
        using System;
        using System.IO;
        using System.Linq;
        using System.Windows.Controls;
        using NinjaTrader.Cbi;
        using NinjaTrader.Gui.Tools;
        using NinjaTrader.NinjaScript;
        using NinjaTrader.Data;
        using System.Collections.Generic;  // Required for List
        #endregion
        
        namespace NinjaTrader.NinjaScript.Indicators
        {
            public class DiamondScanner : Indicator
            {
                private string filePath;
                private bool exportTriggered = false;
                private Button exportButton;
        
                protected override void OnStateChange()
                {
                    if (State == State.SetDefaults)
                    {
                        Description = "Scans manually drawn diamonds and exports data to a CSV file.";
                        Name = "DiamondScanner";
                        IsOverlay = true;
                    }
                    else if (State == State.Configure)
                    {
                        // Path to CSV file in the NinjaTrader User Data directory
                        filePath = Path.Combine(NinjaTrader.Core.Globals.UserDataDir, "DiamondData.csv");
                    }
                    else if (State == State.Historical)
                    {
                        // Create the export button for CSV
                        Dispatcher.InvokeAsync(() =>
                        {
                            exportButton = new Button
                            {
                                Content = "Export Diamonds to CSV",
                                HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
                                VerticalAlignment = System.Windows.VerticalAlignment.Top
                            };
        
                            // Assign method to handle button click
                            exportButton.Click += ExportButton_Click;
        
                            // Add the button to the chart
                            ChartControl.Dispatcher.InvokeAsync(() =>
                            {
                                // Using Parent (the container of chart) to add the button
                                var parentControl = (System.Windows.Controls.Panel)ChartControl.Parent;
                                parentControl.Children.Add(exportButton);
                            });
                        });
                    }
                }
        
                private void ExportButton_Click(object sender, System.Windows.RoutedEventArgs e)
                {
                    try
                    {
                        // Create the file if it doesn't exist and add the header
                        if (!File.Exists(filePath))
                        {
                            using (StreamWriter sw = new StreamWriter(filePath, false))
                            {
                                sw.WriteLine("Time,Open,High,Low,Close");
                            }
                        }
        
                        // Odczekaj 1 sekundę na załadowanie danych
                        System.Threading.Thread.Sleep(1000);
        
                        using (StreamWriter sw = new StreamWriter(filePath, true))
                        {
                            foreach (var drawObject in DrawObjects)
                            {
                                if (drawObject is NinjaTrader.NinjaScript.DrawingTools.Diamond diamond)
                                {
                                    // Check if the tag contains "Diamond"
                                    if (diamond.Tag != null && diamond.Tag.StartsWith("Diamond", StringComparison.OrdinalIgnoreCase))
                                    {
                                        // Get the time of the diamond
                                        DateTime diamondTime = diamond.Anchor.Time;
        
                                        // Print the diamond time for debugging
                                        Print($"Diamond Time: {diamondTime}");
        
                                        // Get the bar data for the corresponding diamond time
                                        for (int i = 0; i < Bars.Count; i++)
                                        {
                                            // Dodatkowe sprawdzenie indeksu
                                            if (i >= Bars.Count)
                                            {
                                                Print($"Error: Invalid bar index (i = {i}, Bars.Count = {Bars.Count})");
                                                continue; // Pomiń tę iterację pętli
                                            }
        
                                            DateTime barTime = Time[i];
        
                                            // If the bar time matches the diamond time (considering date, hour, and minute)
                                            if (diamondTime.Date == barTime.Date && diamondTime.Hour == barTime.Hour && diamondTime.Minute == barTime.Minute)
                                            {
                                                // Write the bar data to the CSV file
                                                sw.WriteLine($"{barTime:yyyy-MM-dd HH:mm:ss},{Opens[i]},{Highs[i]},{Lows[i]},{Closes[i]}");
        
                                                break; // Exit the loop after finding the matching bar
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        Print($"Error writing to CSV file: {ex.Message}");
                    }
                }
            }
        }​
        Last edited by Pabulon; 12-03-2024, 07:30 AM.

        Comment


          #5
          Hello Pabulon,

          To use BarsAgo from a button event you need to put that code inside of TriggerCustomEvent.

          TriggerCustomEvent(o =>
          {​
          // your code

          }, null);

          Comment


            #6
            Dear Jesse

            Thanks for advice, it brought me closer to my goal.
            Now Output acknowledges the location of the Diamond symbol and properly count bars. But it counts from the different sides. One measurement is from the left side of the chart, and the other from the right...

            Number of DrawObjects: 81
            Diamond Time: 15.11.2024 14:20:00
            BarsAgo: 167, Bars.Count: 208
            Exported data for BarsAgo: 167​

            Do You maybe have any suggestion how to solve this issue?

            Code:
            #region Using declarations
            using System;
            using System.IO;
            using System.Linq;
            using System.Windows.Controls;
            using NinjaTrader.Cbi;
            using NinjaTrader.Gui.Tools;
            using NinjaTrader.NinjaScript;
            using NinjaTrader.Data;
            using System.Collections.Generic; // Required for List
            #endregion
            
            namespace NinjaTrader.NinjaScript.Indicators
            {
                public class DiamondScanner : Indicator
                {
                    private string filePath;
                    private bool exportTriggered = false;
                    private Button exportButton;
            
                    protected override void OnStateChange()
                    {
                        if (State == State.SetDefaults)
                        {
                            Description = "Scans manually drawn diamonds and exports data to a CSV file.";
                            Name = "DiamondScanner";
                            IsOverlay = true;
                        }
                        else if (State == State.Configure)
                        {
                            // Path to CSV file in the NinjaTrader User Data directory
                            filePath = Path.Combine(NinjaTrader.Core.Globals.UserDataDir, "DiamondData.csv");
                        }
                        else if (State == State.Historical)
                        {
                            // Create the export button for CSV
                            Dispatcher.InvokeAsync(() =>
                            {
                                exportButton = new Button
                                {
                                    Content = "Export Diamonds to CSV",
                                    HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
                                    VerticalAlignment = System.Windows.VerticalAlignment.Top
                                };
            
                                // Assign method to handle button click
                                exportButton.Click += ExportButton_Click;
            
                                // Add the button to the chart
                                ChartControl.Dispatcher.InvokeAsync(() =>
                                {
                                    // Using Parent (the container of chart) to add the button
                                    var parentControl = (System.Windows.Controls.Panel)ChartControl.Parent;
                                    parentControl.Children.Add(exportButton);
                                });
                            });
                        }
                    }
            
                    private void ExportButton_Click(object sender, System.Windows.RoutedEventArgs e)
                    {
                        // Ensure the export runs only in real-time state
                        if (State != State.Realtime)
                        {
                            Print("Export can only be triggered in real-time state.");
                            return;
                        }
            
                        // Use TriggerCustomEvent to handle BarsAgo correctly
                        TriggerCustomEvent(o =>
                        {
                            try
                            {
                                // Create the file if it doesn't exist and add the header
                                if (!File.Exists(filePath))
                                {
                                    using (StreamWriter sw = new StreamWriter(filePath, false))
                                    {
                                        sw.WriteLine("Time,Open,High,Low,Close");
                                    }
                                }
            
                                using (StreamWriter sw = new StreamWriter(filePath, true))
                                {
                                    Print($"Number of DrawObjects: {DrawObjects.Count()}");
            
                                    foreach (var drawObject in DrawObjects)
                                    {
                                        if (drawObject is NinjaTrader.NinjaScript.DrawingTools.Diamond diamond)
                                        {
                                            // Check if the tag contains "Diamond"
                                            if (diamond.Tag != null && diamond.Tag.StartsWith("Diamond", StringComparison.OrdinalIgnoreCase))
                                            {
                                                // Get the time of the diamond
                                                DateTime diamondTime = diamond.Anchor.Time;
            
                                                // Print the diamond time for debugging
                                                Print($"Diamond Time: {diamondTime}");
            
                                                // Get the bar data for the corresponding diamond time using BarsAgo
                                                int barsAgo = Bars.GetBar(diamondTime);
            
                                                Print($"BarsAgo: {barsAgo}, Bars.Count: {Bars.Count}");
                                                
                                                // Check if barsAgo is within the valid range
                                                if (barsAgo >= 0 && barsAgo < Bars.Count)
                                                {
                                                    // Access bar data and validate indexes
                                                    if (barsAgo < Count)
                                                    {
                                                        sw.WriteLine($"{Time[barsAgo]:yyyy-MM-dd HH:mm:ss},{Open[barsAgo]},{High[barsAgo]},{Low[barsAgo]},{Close[barsAgo]}");
                                                        Print($"Exported data for BarsAgo: {barsAgo}");
                                                    }
                                                    else
                                                    {
                                                        Print($"Error: barsAgo ({barsAgo}) is outside the bounds of bar data.");
                                                    }
                                                }
                                                else
                                                {
                                                    Print($"Error: Invalid barsAgo value ({barsAgo}) for diamond time {diamondTime}");
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Print($"Error writing to CSV file: {ex.Message}");
                            }
                        }, null);
                    }
                }
            }​
            Last edited by Pabulon; 12-03-2024, 10:24 AM.

            Comment


              #7
              Hello Pabulon,

              It looks like you are using the incorrect series, Highs, Opens, Closes, Lows are plural meaning there is an S at the end of the word, this is the multi series price series usage. You need to use the singular High, Open, Low, Close series to get prices. Right now you are supplying a bars ago as a BarsInProgress for the plural series which results in an index error.



              Comment


                #8
                nevermind. I discovered that I need to draw NEW markers on the chart to investigate behavior of the indicator instead of relying on existing ones
                Last edited by Pabulon; 12-03-2024, 01:12 PM.

                Comment


                  #9
                  Dear Jesse

                  I did everything I wanted, it works very well, but I noticed weird behaviour that I don't undestand. Since I added part of code that searches for highest/lowest value in the following 10 bars - when I place, a marker on a chart (i.e. ArrowUp) and export data to CSV file it's all good and working until I do move that marker. If I move it, even by a milimeter on screen, onto next bar, after I try to export data, I'll got an error:
                  Code:
                  Error writing to CSV file: 'barsAgo' needed to be between 0 and 3015 but was 3015
                  Parameter name: barsAgo​
                  Code:
                   else if (drawObject is NinjaTrader.NinjaScript.DrawingTools.ArrowUp arrowUp)
                                              {
                                                  if (arrowUp.Tag != null && arrowUp.Tag.StartsWith("Arrow up", StringComparison.OrdinalIgnoreCase))
                                                  {
                                                      DateTime arrowUpDate = arrowUp.Anchor.Time.Date;
                                                      DateTime arrowUpTime = arrowUp.Anchor.Time;
                                                      int barsAgo = FindBarByTime(arrowUpTime);
                  
                                                      if (barsAgo >= 0 && barsAgo < Bars.Count && arrowUpDate == lastBarDate)
                                                      {
                  
                                                             double abr = Values[0][barsAgo];
                                                          double twoTotal = Values[3][barsAgo];
                                                          double two1R = Values[4][barsAgo];
                                                          double contracts = Math.Floor(Values[7][barsAgo]);
                                                          
                                                          double highestHigh = double.MinValue;
                                                              for (int i = 0; i <= 10 && (barsAgo - i) >= 0; i++)
                                                          {
                                                          highestHigh = Math.Max(highestHigh, High[barsAgo - i]);
                                                          }
                  
                                                          sw.WriteLine($"{Time[barsAgo]:yyyy-MM-dd;HH:mm};;;{abr};{Close[barsAgo]};;{twoTotal};;;{two1R};;;{contracts};;;;;;;;;;;BO;;;;;;;;;;;;;;;;;;;;;;;;;;{highestHigh}");
                                                      }
                                                      else
                                                      {
                                                          Print($"Error: No matching bar found for arrow up time {arrowUpTime}");
                                                      }
                                                  }
                                              }​
                  Why does it happen? How can I solve this issue?


                  EDIT: WRONG DIAGNOSIS

                  What is actualy happening - this problem above ONLY applies to ArrowUp marker and ArrowDown marker. The rest - Square, TriangleUp and TriangleDown can be moved around without error...
                  Sorry for confusing. I'm digging deeper to search for the cause of this.
                  Last edited by Pabulon; 12-04-2024, 01:15 PM.

                  Comment


                    #10
                    Hello Pabulon,

                    The error you are seeing only lets us know some bars ago was incorrect for the use, you would need to find which specific line is having a problem to get a better idea what is happening.

                    Comment


                      #11
                      This is my way of finding bar time - it works for Square, Dot, TriangleUp, TriangleDown - no conditions. For ArrowUp and ArrowDown it works only if they are not previously moved on the chart.

                      Code:
                              private int FindBarByTime(DateTime markerTime)
                              {
                                  for (int i = 0; i < Bars.Count; i++)
                                  {
                                      if (Time[i] == markerTime)
                                          return i;
                                  }
                                  return -1;
                              }
                      
                              private void ExportButton_Click(object sender, System.Windows.RoutedEventArgs e)
                              {
                                  TriggerCustomEvent(o =>
                                  {
                                      try
                                      {
                                          // Pobranie daty ostatniej świecy na wykresie
                                          DateTime lastBarDate = Bars.GetTime(CurrentBar).Date;
                                                      Print($"Last bar date: {lastBarDate}");
                                          // Create the CSV file if it doesn't exist
                                          if (!File.Exists(filePath))
                                          {
                                              using (StreamWriter sw = new StreamWriter(filePath, false))
                                              {
                                                  // Write the header to the CSV file
                                                  sw.WriteLine("Date;Time;;;ABR;Close;;Total;;;1R;;;Contracts;;;;;;;;;;;Setup;Secondary;;;;;;;;;;;;;;;;;;;;;;;;;;after 10 bar");
                                              }
                                          }
                      
                                          using (StreamWriter sw = new StreamWriter(filePath, true))
                                          {
                                              foreach (var drawObject in DrawObjects)
                                              {
                                                  if (drawObject is NinjaTrader.NinjaScript.DrawingTools.Square square)
                                                  {
                                                      if (square.Tag != null && square.Tag.StartsWith("Square", StringComparison.OrdinalIgnoreCase))
                                                      {
                                                          DateTime squareDate = square.Anchor.Time.Date;
                                                          DateTime squareTime = square.Anchor.Time;
                                                          int barsAgo = FindBarByTime(squareTime);
                      
                                                          if (barsAgo >= 0 && barsAgo < Bars.Count && squareDate == lastBarDate)
                                                          {
                                                                 double abr = Values[0][barsAgo];
                                                              double oneTotal = Values[1][barsAgo];
                                                              double one1R = Values[2][barsAgo];
                                                              double contracts = Math.Floor(Values[7][barsAgo]);
                      
                                                              sw.WriteLine($"{Time[barsAgo]:yyyy-MM-dd;HH:mm};;;{abr};{Close[barsAgo]};;{oneTotal};;;{one1R};;;{contracts};;;;;;;;;;;BO;Big-BO");
                                                          }
                                                          else
                                                          {
                                                              Print($"Error: No matching bar found for square time {squareTime}");
                                                          }
                                                      }
                                                  }​​

                      Comment


                        #12
                        Hello Pabulon,

                        We still need to know which line is having an error, which specific line is having a problem?

                        Comment


                          #13
                          I'd say its this:
                          Code:
                          int barsAgo = FindBarByTime(squareTime);
                          But with huge disclaimer - it only plots error for ArrowUp or ArrowDown if they are previously moved on the chart.
                          I even asked AI for this and it produced this:
                          The error occurs because for markers like ArrowUp and ArrowDown, the internal time coordinates change after they are moved on the chart. This happens because NinjaTrader recalculates the Anchor.Time for these markers, which causes the FindBarByTime function to fail in finding the correct bar based on the updated time. As a result, the barsAgo value goes out of range.

                          Why do other markers work correctly?
                          Square, TriangleUp, and TriangleDown have more static time coordinates and are less susceptible to changes caused by user interactions on the chart. In the case of ArrowUp and ArrowDown, NinjaTrader treats them differently, requiring additional validation.
                          I got some success with using for loop

                          int barsAgo = -1;
                          for (int i = 0; i < Bars.Count - 1; i++)
                          {
                          DateTime barTime = Bars.GetTime(i); // Czas świecy na barze i

                          if (barTime <= arrowTime && Bars.GetTime(i + 1) > arrowTime)
                          {
                          barsAgo = CurrentBar - i;

                          DateTime analyzedBarTime = Bars.GetTime(i);
                          Print($"Czas analizowanej świecy: {analyzedBarTime}");

                          DateTime nextBarTime = Bars.GetTime(i + 1);
                          Print($"Czas następnej świecy: {nextBarTime}");

                          break;​
                          But sometimes the time is correct, sometimes it's 1 bar to the left or right. It's not consistent. But it doesn't generate any errors in this scenario. Just the time sometimes is like... rounded in wrong direction, I don't know I'm super confused.

                          Comment


                            #14
                            Hello Pabulon,

                            In regard to AI I would not suggest using that, the information ai provies is usually incorrect and we see that a lot. We would still need to know which specific line of code is having an error, FindByTime is a custom method you made so you need to dig into that method if that is the line causing an error. There is another line having an error inside that method using a bars ago. I have included a disclaimer about AI tools below.

                            Drawing tools use a Slot system which is different than bars ago so trying to find a specific bar by an anchors time which is not a specific bar time is not directly possible, you may get a bar near the anchor which was not the target bar. To be able to get accurate matching times in script your scripts would have to draw the object using a bar time which it is attached to so the times exactly match. Manually placed objects do not rely on the series your script is attached to so it could be variable.


                            From our experience at this time, ChatGpt and other AI models are not adequate at generating valid NinjaScript code that function as the user has intentioned. We often find that these tools generate code that will call non-existent properties and methods, use improper classes or inheritance, and may have incorrect logic. Using these tools for general NinjaScript learning information may also provide incorrect responses. We highly encourage that you create a new NinjaScript yourself using the NinjaScript Editor and avoid any AI based coding tools.

                            While it would not be within our support model to assist with scripts generated or checked by ai tools, we would be happy to provide insight for any direct specific inquiries you may have if you would like to create this script yourself. Our support is able to assist with finding resources in our help guide as well as simple examples, and we are happy to provide guidance on how you can debug the script while running it on your machine. To start learning NinjaScript I would suggest the following link as a starting point.


                            You can also contact a professional NinjaScript Consultant who would be eager to create or modify this script at your request or assist you with your script. The NinjaTrader Ecosystem has affiliate contacts who provide educational as well as consulting services. Please let me know if you would like a list of affiliate consultants who would be happy to create this script or any others at your request or provide one on one educational services.​

                            Comment


                              #15
                              Dear Jesse

                              I can't even say that some line creates an error because after I plotted some errors it became clear that it's just the way it is - ArrowUp or Down after being moved, somehow loose their accuracy that you were talking about above. Though so far, all markers besides ArrowUp/Down that are not being moved on the chart had 100% accuracy - by accuracy I mean, their AnchorTime matches BarTime correclty even when are being drawn "by hand" and export correct values to CSV files.
                              About AI - I agree and don't agree at the same time. I received tremendeus help from it but it required dozens of tries sometimes to accomplish what I've wanted.

                              Okay I get it! When you move i.e. Squate, Dot, Triangles on the chart, they only jump every 5minutes on the chart. But ArrowUp and ArrowDown they move by some other weird amount and generate seconds in their AnchorTime. That's why they cause problems when moved. Can it be done so that they also jump every 5 minutes?

                              It's solved - I just at first gathered the time, then rounded it fo full 5min and exported that. Walk-around but works.
                              Last edited by Pabulon; 12-04-2024, 04:08 PM.

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by Geovanny Suaza, 02-11-2026, 06:32 PM
                              0 responses
                              574 views
                              0 likes
                              Last Post Geovanny Suaza  
                              Started by Geovanny Suaza, 02-11-2026, 05:51 PM
                              0 responses
                              333 views
                              1 like
                              Last Post Geovanny Suaza  
                              Started by Mindset, 02-09-2026, 11:44 AM
                              0 responses
                              101 views
                              0 likes
                              Last Post Mindset
                              by Mindset
                               
                              Started by Geovanny Suaza, 02-02-2026, 12:30 PM
                              0 responses
                              553 views
                              1 like
                              Last Post Geovanny Suaza  
                              Started by RFrosty, 01-28-2026, 06:49 PM
                              0 responses
                              551 views
                              1 like
                              Last Post RFrosty
                              by RFrosty
                               
                              Working...
                              X