Announcement

Collapse

Looking for a User App or Add-On built by the NinjaTrader community?

Visit NinjaTrader EcoSystem and our free User App Share!

Have a question for the NinjaScript developer community? Open a new thread in our NinjaScript File Sharing Discussion Forum!
See more
See less

Partner 728x90

Collapse

Problem writing to file during strategy optimisation

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

    Problem writing to file during strategy optimisation

    Hi, I'm trying to write data to file during strategy optimisation (NT7 Beta 14). I've posted the code below which I'm using and is basically the SampleMACrossover strategy adapted to write custom performance data to file. There are options in the code for two different reports which can be toggled on and off. Trouble is when I run the code (and enable one of the reports) in the Strategy Analyzer I get an error like this:

    19/04/2010 22:01:13 Default File write error for file name 'C:\Automation Data\2010419 2153 SGMACrossover View360Report.csv' Error 'The process cannot access the file 'C:\Automation Data\2010419 2153 SGMACrossover View360Report.csv' because it is being used by another process.'

    I've used sections of code found on the forums to handle the writing to file and I've tried to experiment with the Dispose() method, as mentioned on the forums, to clean up resources but nothing seems to help, the file is always in use 'by another process'.

    The results I'd like to achieve are;

    1. During an optimisation basket test, when the last bar of an instrument is reached then a single line summary of performance for that instrument & parameter set is written to file. (Optimisation Performance Summary)

    2. During an optimisation basket test the details of every trade are written to a different file, with data formatted for use in Brute View360 walk forward software.

    3. Implement a buffer to improve write efficiency (Not sure how to do this though!)

    Can you see what I'm doing wrong in the code / help to get it working?

    Many thanks

    Riskybiz

    Code:
    #region Using declarations
    using System;
    using System.ComponentModel;
    using System.Diagnostics;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Xml.Serialization;
    using NinjaTrader.Cbi;
    using NinjaTrader.Data;
    using NinjaTrader.Indicator;
    using NinjaTrader.Strategy;
    using System.IO;
    #endregion
    
    // This namespace holds all strategies and is required. Do not change it.
    namespace NinjaTrader.Strategy
    {
    	/// <summary>
    	/// Simple moving average cross over strategy.
    	/// </summary>
    	[Description("Simple moving average cross over strategy, with View360 Export code.")]
    	public class SGMACrossOver : Strategy
    	{
    		#region Variables
    		private int		fast	= 10;
    		private int		slow	= 25;
    		
    		private bool view360Export = false;
    		private string optimisationFile; 
    		
    		private bool performanceReport;
    		private string performanceReportFile;// = "PerformanceFile.csv";
    		
    		private string dateString;
    		private string perfHeadString;
    		private string perfString;
    				
    		private double np;
    		
    		private DateTime timeStamp = DateTime.Now;
    						
    		#endregion
    
    		/// <summary>
    		/// This method is used to configure the strategy and is called once before any strategy method is called.
    		/// </summary>
    		protected override void Initialize()
    		{
    			SMA(Fast).Plots[0].Pen.Color = Color.Orange;
    			SMA(Slow).Plots[0].Pen.Color = Color.Green;
    
    			Add(SMA(Fast));
    			Add(SMA(Slow));
    
    			CalculateOnBarClose	= true;
    								
    		}
    
    		//last bar on chart		
    		[Browsable(false)]
    		public bool LastBarOnChart
    		{
    		 get
    		 {
    		 if (!CalculateOnBarClose && CurrentBar == Bars.Count - 1)
    		 return true;
    		 else if (CalculateOnBarClose && CurrentBar == Bars.Count - 2)
    		 return true;
    
    		 return false;
    		 }
    		}
    		
    		//write to file
    		private void WriteFile(string fileName, string line)
    		 {
    		 // Creates the file path
    		 string file = /*NinjaTrader.Cbi.Core.UserDataDir + @"log" +*/ fileName;
    		 // Writes out a line to the specified file name
    		 try
    		 {
    		 using (System.IO.StreamWriter writer = new System.IO.StreamWriter(file))
    		 {
    		   	writer.WriteLine(line);
    		    
    			//writer.Flush();
    		    //writer.Close();
    			//writer.Dispose();
    		   }
    		 }
    		 catch (System.Exception exp)
    		  {
    		  Log("File write error for file name '" + fileName + "' Error '" + exp.Message + "'", LogLevel.Warning);
    		  }
    		 }
    		
    	
    		
    		//on bar update
    		protected override void OnBarUpdate()
    		{
    		
    		 // strategy	
    		 {
    			if (CrossAbove(SMA(Fast), SMA(Slow), 1))
    			    EnterLong();
    			else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
    			    EnterShort();
    		 }
    		
    		try
    		 {
    		//view360 export
    		if (Performance.AllTrades.Count > 0 && CurrentBar == Bars.Count-2 && view360Export == true)
    		 {
    		 	if(optimisationFile == null)//create filename if it doesn't exist already
    			{
    			dateString = timeStamp.Year.ToString() + timeStamp.Month.ToString() + timeStamp.Day.ToString() + "  " +
    				timeStamp.Hour.ToString() + timeStamp.Minute.ToString();//date & time stamp the file to make it unique
    			
    			optimisationFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover View360 Data.csv";
    			}
    				
    			
    		for (int i = 0; i < Performance.AllTrades.Count; i++)
    		 {
    			Trade lastTrade = Performance.AllTrades[i];
    			double lastProfit = lastTrade.ProfitCurrency *
    			lastTrade.Quantity;
    			lastProfit = Math.Round(lastProfit,2);
    			int MP = 0;
    		if (lastTrade.Entry.MarketPosition == MarketPosition.Short)
    		 {
    		    MP = -1;
    		 }
    		else if (lastTrade.Entry.MarketPosition == MarketPosition.Long)
    		 {
    			MP = 1;
    		 }
    		
            string input1 = fast.ToString();
    		string input2 = slow.ToString();
    		string input3 = " ";
    		string input4 = " ";
    		string input5 = " ";
    		string input6 = " ";
    		string input7 = " ";
    		string input8 = " ";
    		string input9 = " ";
    		string input10 = " ";
    		
    		WriteFile(optimisationFile, lastTrade.Entry.Instrument.ToString() + "," +
    		input1 + "," + input2 + "," + input3 + "," +
    		input4 + "," + input5 + "," + input6 + "," +
    		input7 + "," + input8 + "," + input9 + "," +
    		input10 + "," + lastTrade.Quantity.ToString() +
    		"," + MP.ToString() + "," +
    		lastTrade.Entry.Time.ToShortDateString() + "," +
    		lastTrade.Entry.Price.ToString() + "," +
    		lastTrade.Exit.Time.ToShortDateString() + "," +
    		lastTrade.Exit.Price.ToString() + "," +
    		lastProfit.ToString());
    		}
    		}
    	}//view360report
    	catch (Exception e)
    	 {
    		Log("Error: View 360 Export Code Error" , NinjaTrader.Cbi.LogLevel.Error);
    		throw(e);
         }
    	
    	//performance report
    	try
    	{
    	if(LastBarOnChart == true && performanceReport == true)
    	{
    				
    		if(performanceReportFile == null)//create filename if it doesn't exist already
    		{
    			dateString = timeStamp.Year.ToString() + timeStamp.Month.ToString() + timeStamp.Day.ToString() + "  " +
    				timeStamp.Hour.ToString() + timeStamp.Minute.ToString();//date & time stamp the file to make it unique
    			
    			performanceReportFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover Optimisation Performance Summary.csv";
    			perfHeadString = "Instrument Name, Fast MA, Slow MA, NetProfit";
    			WriteFile(performanceReportFile, perfHeadString);
    		}
    				
    		np = (Performance.AllTrades.TradesPerformance.GrossProfit - Performance.AllTrades.TradesPerformance.GrossLoss);
    		
    		perfString = Instrument.FullName + "," + fast.ToString() + "," + slow.ToString() + "," + np.ToString();
    		WriteFile(performanceReportFile, perfString);
    				
    	}//performance report
    	}//try
    	catch (Exception e)
    	 {
    		Log("Error: Optimisation Performance Report Error" , NinjaTrader.Cbi.LogLevel.Error);
    		throw(e);
         }//catch
    	
    	
    }//on bar update	
    
    		
    		#region Properties
    		/// <summary>
    		/// </summary>
    		[Description("Period for fast MA")]
    		[Category("Parameters")]
    		public int Fast
    		{
    			get { return fast; }
    			set { fast = Math.Max(1, value); }
    		}
    
    		/// <summary>
    		/// </summary>
    		[Description("Period for slow MA")]
    		[Category("Parameters")]
    		public int Slow
    		{
    			get { return slow; }
    			set { slow = Math.Max(1, value); }
    		}
    		//View360 addition
    		[Description("Enable View360 Data Export; Use During Optimisations")]
    		[Category("Parameters")]
    		public bool Export_View360_Report
    		{
    		get { return view360Export; }
    		set { view360Export = value; }
    		}
    		
    		//Performance Summary
    		[Description("Enable Performance Summary Report; Use During Optimisations")]
    		[Category("Parameters")]
    		public bool Export_Performance_Summary
    		{
    		get { return performanceReport; }
    		set { performanceReport = value; }
    		}
    		
    		//File Date & Time Stamp
    		[ReadOnlyAttribute(true)]
    		[Description("Date & Time Stamp For Output Files")]
    		[Category("Parameters")]
    		public DateTime Time_Stamp
    		{
    		get { return timeStamp; }
    		set { timeStamp = value; }
    		}
    		
    		#endregion
    	}
    }

    #2
    Riskybiz,

    What you can try is to actually use the actual Dispose() method. Maybe you will have different results then: http://www.ninjatrader-support.com/H...e.html?Dispose
    Josh P.NinjaTrader Customer Service

    Comment


      #3
      Still not working

      Josh, in my previous post I'd commented out the lines I'd been experimenting with, but have now added the:

      Code:
      // Clean up your resources here 
                      public override void Dispose() 
      		{ 
          		base.Dispose(); 
      		}
      code section you suggest and also uncommented:

      Code:
      writer.Dispose();
      to give:

      Code:
      #region Using declarations
      using System;
      using System.ComponentModel;
      using System.Diagnostics;
      using System.Drawing;
      using System.Drawing.Drawing2D;
      using System.Xml.Serialization;
      using NinjaTrader.Cbi;
      using NinjaTrader.Data;
      using NinjaTrader.Indicator;
      using NinjaTrader.Strategy;
      using System.IO;
      #endregion
      
      // This namespace holds all strategies and is required. Do not change it.
      namespace NinjaTrader.Strategy
      {
      	/// <summary>
      	/// Simple moving average cross over strategy.
      	/// </summary>
      	[Description("Simple moving average cross over strategy, with View360 Export code.")]
      	public class SGMACrossOver : Strategy
      	{
      		#region Variables
      		private int		fast	= 10;
      		private int		slow	= 25;
      		
      		private bool view360Export = false;
      		private string optimisationFile; 
      		
      		private bool performanceReport;
      		private string performanceReportFile;// = "PerformanceFile.csv";
      		
      		private string dateString;
      		private string perfHeadString;
      		private string perfString;
      				
      		private double np;
      		
      		private DateTime timeStamp = DateTime.Now;
      						
      		#endregion
      
      		/// <summary>
      		/// This method is used to configure the strategy and is called once before any strategy method is called.
      		/// </summary>
      		protected override void Initialize()
      		{
      			SMA(Fast).Plots[0].Pen.Color = Color.Orange;
      			SMA(Slow).Plots[0].Pen.Color = Color.Green;
      
      			Add(SMA(Fast));
      			Add(SMA(Slow));
      
      			CalculateOnBarClose	= true;
      								
      		}
      
      		//last bar on chart		
      		[Browsable(false)]
      		public bool LastBarOnChart
      		{
      		 get
      		 {
      		 if (!CalculateOnBarClose && CurrentBar == Bars.Count - 1)
      		 return true;
      		 else if (CalculateOnBarClose && CurrentBar == Bars.Count - 2)
      		 return true;
      
      		 return false;
      		 }
      		}
      		
      		//write to file
      		private void WriteFile(string fileName, string line)
      		 {
      		 // Creates the file path
      		 string file = /*NinjaTrader.Cbi.Core.UserDataDir + @"log" +*/ fileName;
      		 // Writes out a line to the specified file name
      		 try
      		 {
      		 using (System.IO.StreamWriter writer = new System.IO.StreamWriter(file))
      		 {
      		   	writer.WriteLine(line);
      		    
      			//writer.Flush();
      		    //writer.Close();
      			writer.Dispose();
      		   }
      		 }
      		 catch (System.Exception exp)
      		  {
      		  Log("File write error for file name '" + fileName + "' Error '" + exp.Message + "'", LogLevel.Warning);
      		  }
      		 }
      		
      		// Clean up your resources here 
      		public override void Dispose() 
      		{ 
          		base.Dispose(); 
      		}
      		
      		//on bar update
      		protected override void OnBarUpdate()
      		{
      		
      		 // strategy	
      		 {
      			if (CrossAbove(SMA(Fast), SMA(Slow), 1))
      			    EnterLong();
      			else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
      			    EnterShort();
      		 }
      		
      		try
      		 {
      		//view360 export
      		if (Performance.AllTrades.Count > 0 && CurrentBar == Bars.Count-2 && view360Export == true)
      		 {
      		 	if(optimisationFile == null)//create filename if it doesn't exist already
      			{
      			dateString = timeStamp.Year.ToString() + timeStamp.Month.ToString() + timeStamp.Day.ToString() + "  " +
      				timeStamp.Hour.ToString() + timeStamp.Minute.ToString();//date & time stamp the file to make it unique
      			
      			optimisationFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover View360 Data.csv";
      			}
      				
      			
      		for (int i = 0; i < Performance.AllTrades.Count; i++)
      		 {
      			Trade lastTrade = Performance.AllTrades[i];
      			double lastProfit = lastTrade.ProfitCurrency *
      			lastTrade.Quantity;
      			lastProfit = Math.Round(lastProfit,2);
      			int MP = 0;
      		if (lastTrade.Entry.MarketPosition == MarketPosition.Short)
      		 {
      		    MP = -1;
      		 }
      		else if (lastTrade.Entry.MarketPosition == MarketPosition.Long)
      		 {
      			MP = 1;
      		 }
      		
              string input1 = fast.ToString();
      		string input2 = slow.ToString();
      		string input3 = " ";
      		string input4 = " ";
      		string input5 = " ";
      		string input6 = " ";
      		string input7 = " ";
      		string input8 = " ";
      		string input9 = " ";
      		string input10 = " ";
      		
      		WriteFile(optimisationFile, lastTrade.Entry.Instrument.ToString() + "," +
      		input1 + "," + input2 + "," + input3 + "," +
      		input4 + "," + input5 + "," + input6 + "," +
      		input7 + "," + input8 + "," + input9 + "," +
      		input10 + "," + lastTrade.Quantity.ToString() +
      		"," + MP.ToString() + "," +
      		lastTrade.Entry.Time.ToShortDateString() + "," +
      		lastTrade.Entry.Price.ToString() + "," +
      		lastTrade.Exit.Time.ToShortDateString() + "," +
      		lastTrade.Exit.Price.ToString() + "," +
      		lastProfit.ToString());
      		}
      		}
      	}//view360report
      	catch (Exception e)
      	 {
      		Log("Error: View 360 Export Code Error" , NinjaTrader.Cbi.LogLevel.Error);
      		throw(e);
           }
      	
      	//performance report
      	try
      	{
      	if(LastBarOnChart == true && performanceReport == true)
      	{
      				
      		if(performanceReportFile == null)//create filename if it doesn't exist already
      		{
      			dateString = timeStamp.Year.ToString() + timeStamp.Month.ToString() + timeStamp.Day.ToString() + "  " +
      				timeStamp.Hour.ToString() + timeStamp.Minute.ToString();//date & time stamp the file to make it unique
      			
      			performanceReportFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover Optimisation Performance Summary.csv";
      			perfHeadString = "Instrument Name, Fast MA, Slow MA, NetProfit";
      			WriteFile(performanceReportFile, perfHeadString);
      		}
      				
      		np = (Performance.AllTrades.TradesPerformance.GrossProfit - Performance.AllTrades.TradesPerformance.GrossLoss);
      		
      		perfString = Instrument.FullName + "," + fast.ToString() + "," + slow.ToString() + "," + np.ToString();
      		WriteFile(performanceReportFile, perfString);
      				
      	}//performance report
      	}//try
      	catch (Exception e)
      	 {
      		Log("Error: Optimisation Performance Report Error" , NinjaTrader.Cbi.LogLevel.Error);
      		throw(e);
           }//catch
      	
      	
      }//on bar update	
      
      		
      		#region Properties
      		/// <summary>
      		/// </summary>
      		[Description("Period for fast MA")]
      		[Category("Parameters")]
      		public int Fast
      		{
      			get { return fast; }
      			set { fast = Math.Max(1, value); }
      		}
      
      		/// <summary>
      		/// </summary>
      		[Description("Period for slow MA")]
      		[Category("Parameters")]
      		public int Slow
      		{
      			get { return slow; }
      			set { slow = Math.Max(1, value); }
      		}
      		//View360 addition
      		[Description("Enable View360 Data Export; Use During Optimisations")]
      		[Category("Parameters")]
      		public bool Export_View360_Report
      		{
      		get { return view360Export; }
      		set { view360Export = value; }
      		}
      		
      		//Performance Summary
      		[Description("Enable Performance Summary Report; Use During Optimisations")]
      		[Category("Parameters")]
      		public bool Export_Performance_Summary
      		{
      		get { return performanceReport; }
      		set { performanceReport = value; }
      		}
      		
      		//File Date & Time Stamp
      		[ReadOnlyAttribute(true)]
      		[Description("Date & Time Stamp For Output Files")]
      		[Category("Parameters")]
      		public DateTime Time_Stamp
      		{
      		get { return timeStamp; }
      		set { timeStamp = value; }
      		}
      		
      		#endregion
      	}
      }
      But still I get the error that the 'file is in use by another process'. I was under the impression that enclosing the StreamWriter in a 'using' statement like this:

      Code:
      using (System.IO.StreamWriter writer = new System.IO.StreamWriter(file))
      would automatically clean up the resources as mentioned here:

      Implements a TextWriter for writing characters to a stream in a particular encoding.


      Quote:

      "The following example shows how to use a StreamWriter object to write a file that lists the directories on the C drive, and then uses a StreamReader object to read and display each directory name. A good practice is to use these objects in a using statement so that the unmanaged resources are correctly disposed. The using statement automatically calls Dispose on the object when the code that is using it has completed."

      So I'm unsure of whether or not the Dispose method is actually required or not. The text writing code section I'm using was pulled from:



      by NinjaTrader_Ray and doesn't originally require Dispose().

      The results I'm getting during an optimisation basket test are: I get the file created in the correct folder containing a single line with the data relating to the final instrument in the 'basket' and many, many error lines in the log (one for each optimiser run, I expect) with the 'file in use by another process' error

      Just a thought, and I'm by no means an expert on this, but could 'file in use by another process' be because my dual core machine is running multiple optimisation threads which are conflicting by both trying to write to the file at the same time?

      I need to sort this out because analysing the optimisation performance data in Excel is a cornerstone of my system development. Not sure what to try next? Any ideas?

      Thanks

      Riskybiz

      Comment


        #4
        If you use StreamWriter() inside using(), then you don't need to apply any action after the write operations. This is guaranteed by C#, period.

        StreamWriter() (and StreamReader() open a file with exclusive access rights, so no other reader/writer can open that file for access. With other words, if you get the error message you described, then another reader/writer has access already. That could also be a text editor, they claim exclusive access too sometime.

        Regards
        Ralph

        PS: If you want to debug the number of access attempts, you could define a static counter variable inside the concerning class. Increment and print this variable when entering the using-statement. Decrement and print this variable before the using-statement is left. This way you could see if there is an unexpected confict causes by your code.
        Last edited by Ralph; 04-20-2010, 04:12 AM. Reason: Debuggin Proposal

        Comment


          #5
          Guys, please be aware that optimizing strategies is multithreaded, meaning multiple threads run multiple strategy instances the same time. Any code doing some custom resource management (like on files), needs to be reflective of that.

          Note: introducing "locking" logic actually might defeat the purpose, since the benefit of multi cores/multi threading might be lost by introducing "critical sections".

          Comment


            #6
            File Access Counter

            I've added a counter variable to the code as Ralph mentioned:

            Code:
            #region Using declarations
            using System;
            using System.ComponentModel;
            using System.Diagnostics;
            using System.Drawing;
            using System.Drawing.Drawing2D;
            using System.Xml.Serialization;
            using NinjaTrader.Cbi;
            using NinjaTrader.Data;
            using NinjaTrader.Indicator;
            using NinjaTrader.Strategy;
            using System.IO;
            #endregion
            
            // This namespace holds all strategies and is required. Do not change it.
            namespace NinjaTrader.Strategy
            {
            	/// <summary>
            	/// Simple moving average cross over strategy.
            	/// </summary>
            	[Description("Simple moving average cross over strategy, with View360 Export code.")]
            	public class SGMACrossOver : Strategy
            	{
            		#region Variables
            		private int		fast	= 10;
            		private int		slow	= 25;
            		
            		private bool view360Export = false;
            		private string optimisationFile; 
            		
            		private bool performanceReport = false;
            		private string performanceReportFile;
            		
            		private string dateString;
            		private string perfHeadString;
            		private string perfString;
            				
            		private double np;
            		
            		private DateTime timeStamp = DateTime.Now;
            		
            		private static int accessCounter = 0;// will only ever be one variable 'accessCounter', no matter how many class instances
            		
            		#endregion
            
            		/// <summary>
            		/// This method is used to configure the strategy and is called once before any strategy method is called.
            		/// </summary>
            		protected override void Initialize()
            		{
            			SMA(Fast).Plots[0].Pen.Color = Color.Orange;
            			SMA(Slow).Plots[0].Pen.Color = Color.Green;
            
            			Add(SMA(Fast));
            			Add(SMA(Slow));
            
            			CalculateOnBarClose	= true;
            								
            		}
            
            		//last bar on chart		
            		[Browsable(false)]
            		public bool LastBarOnChart
            		{
            		 get
            		 {
            		 if (!CalculateOnBarClose && CurrentBar == Bars.Count - 1)
            		 return true;
            		 else if (CalculateOnBarClose && CurrentBar == Bars.Count - 2)
            		 return true;
            
            		 return false;
            		 }
            		}
            		
            		//write to file
            		private void WriteFile(string fileName, string line)
            		 {
            		 // Creates the file path
            		 string file = /*NinjaTrader.Cbi.Core.UserDataDir + @"log" +*/ fileName;
            		 // Writes out a line to the specified file name
            		 try
            		 {
            		 accessCounter += 1;//increment
            		 Print("File Access Attempts: Entering " + accessCounter.ToString());
            		 using (System.IO.StreamWriter writer = new System.IO.StreamWriter(file))
            		 {
            		 	writer.WriteLine(line);
            		    accessCounter -= 1;//decrement
            			Print("File Access Attempts: Exiting " + accessCounter.ToString());
            		 }
            		 }
            		 catch (System.Exception exp)
            		  {
            		  Log("File write error for file name '" + fileName + "' Error '" + exp.Message + "'", LogLevel.Warning);
            		  }
            		 }
            		//on bar update
            		protected override void OnBarUpdate()
            		{
            		
            		 // strategy	
            		 {
            			if (CrossAbove(SMA(Fast), SMA(Slow), 1))
            			    EnterLong();
            			else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
            			    EnterShort();
            		 }
            		
            		try
            		 {
            		//view360 export
            		if (Performance.AllTrades.Count > 0 && CurrentBar == Bars.Count-2 && view360Export == true)
            		 {
            		 	if(optimisationFile == null)//create filename if it doesn't exist already
            			{
            			dateString = timeStamp.Year.ToString() + timeStamp.Month.ToString() + timeStamp.Day.ToString() + "  " +
            				timeStamp.Hour.ToString() + timeStamp.Minute.ToString();//date & time stamp the file to make it unique
            			
            			optimisationFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover View360 Data.csv";
            			}
            				
            			
            		for (int i = 0; i < Performance.AllTrades.Count; i++)
            		 {
            			Trade lastTrade = Performance.AllTrades[i];
            			double lastProfit = lastTrade.ProfitCurrency *
            			lastTrade.Quantity;
            			lastProfit = Math.Round(lastProfit,2);
            			int MP = 0;
            		if (lastTrade.Entry.MarketPosition == MarketPosition.Short)
            		 {
            		    MP = -1;
            		 }
            		else if (lastTrade.Entry.MarketPosition == MarketPosition.Long)
            		 {
            			MP = 1;
            		 }
            		
                    string input1 = fast.ToString();
            		string input2 = slow.ToString();
            		string input3 = " ";
            		string input4 = " ";
            		string input5 = " ";
            		string input6 = " ";
            		string input7 = " ";
            		string input8 = " ";
            		string input9 = " ";
            		string input10 = " ";
            		
            		WriteFile(optimisationFile, lastTrade.Entry.Instrument.ToString() + "," +
            		input1 + "," + input2 + "," + input3 + "," +
            		input4 + "," + input5 + "," + input6 + "," +
            		input7 + "," + input8 + "," + input9 + "," +
            		input10 + "," + lastTrade.Quantity.ToString() +
            		"," + MP.ToString() + "," +
            		lastTrade.Entry.Time.ToShortDateString() + "," +
            		lastTrade.Entry.Price.ToString() + "," +
            		lastTrade.Exit.Time.ToShortDateString() + "," +
            		lastTrade.Exit.Price.ToString() + "," +
            		lastProfit.ToString());
            		}
            		}
            	}//view360report
            	catch (Exception e)
            	 {
            		Log("Error: View 360 Export Code Error" , NinjaTrader.Cbi.LogLevel.Error);
            		throw(e);
                 }
            	
            	//performance report
            	try
            	{
            	if(LastBarOnChart == true && performanceReport == true)
            	{
            				
            		if(performanceReportFile == null)//create filename if it doesn't exist already
            		{
            			dateString = timeStamp.Year.ToString() + timeStamp.Month.ToString() + timeStamp.Day.ToString() + "  " +
            				timeStamp.Hour.ToString() + timeStamp.Minute.ToString();//date & time stamp the file to make it unique
            			
            			performanceReportFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover Optimisation Performance Summary.csv";
            			perfHeadString = "Instrument Name, Fast MA, Slow MA, NetProfit";
            			WriteFile(performanceReportFile, perfHeadString);
            		}
            				
            		np = (Performance.AllTrades.TradesPerformance.GrossProfit - Performance.AllTrades.TradesPerformance.GrossLoss);
            		
            		perfString = Instrument.FullName + "," + fast.ToString() + "," + slow.ToString() + "," + np.ToString();
            		WriteFile(performanceReportFile, perfString);
            				
            	}//performance report
            	}//try
            	catch (Exception e)
            	 {
            		Log("Error: Optimisation Performance Report Error" , NinjaTrader.Cbi.LogLevel.Error);
            		throw(e);
                 }//catch
            	
            	
            }//on bar update	
            
            		
            		#region Properties
            		/// <summary>
            		/// </summary>
            		[Description("Period for fast MA")]
            		[Category("Parameters")]
            		public int Fast
            		{
            			get { return fast; }
            			set { fast = Math.Max(1, value); }
            		}
            
            		/// <summary>
            		/// </summary>
            		[Description("Period for slow MA")]
            		[Category("Parameters")]
            		public int Slow
            		{
            			get { return slow; }
            			set { slow = Math.Max(1, value); }
            		}
            		//View360 addition
            		[Description("Enable View360 Data Export; Use During Optimisations")]
            		[Category("Parameters")]
            		public bool Export_View360_Report
            		{
            		get { return view360Export; }
            		set { view360Export = value; }
            		}
            		
            		//Performance Summary
            		[Description("Enable Performance Summary Report; Use During Optimisations")]
            		[Category("Parameters")]
            		public bool Export_Performance_Summary
            		{
            		get { return performanceReport; }
            		set { performanceReport = value; }
            		}
            		
            		//File Date & Time Stamp
            		[ReadOnlyAttribute(true)]
            		[Description("Date & Time Stamp For Output Files")]
            		[Category("Parameters")]
            		public DateTime Time_Stamp
            		{
            		get { return timeStamp; }
            		set { timeStamp = value; }
            		}
            		
            		#endregion
            	}
            }
            and the output bears out what Dierk says. When run in a strategy optimisation then the write to file code yields an increasing number of file access attempts, which are presumably conflicting, as shown in this Output Window snippet:

            Code:
            File Access Attempts: Entering 1
            File Access Attempts: Entering 2
            File Access Attempts: Exiting 1
            File Access Attempts: Entering 2
            File Access Attempts: Exiting 1
            File Access Attempts: Entering 2
            File Access Attempts: Exiting 1
            File Access Attempts: Entering 3
            File Access Attempts: Exiting 2
            File Access Attempts: Entering 3
            File Access Attempts: Entering 2
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Exiting 3
            File Access Attempts: Entering 4
            File Access Attempts: Entering 5
            File Access Attempts: Entering 6
            File Access Attempts: Exiting 5
            File Access Attempts: Entering 6
            File Access Attempts: Exiting 5
            File Access Attempts: Entering 6
            File Access Attempts: Exiting 5
            File Access Attempts: Entering 6
            File Access Attempts: Exiting 5
            File Access Attempts: Entering 6
            File Access Attempts: Exiting 5
            File Access Attempts: Entering 6
            File Access Attempts: Entering 7
            File Access Attempts: Exiting 6
            File Access Attempts: Entering 7
            File Access Attempts: Exiting 6
            File Access Attempts: Entering 7
            File Access Attempts: Entering 8
            File Access Attempts: Exiting 7
            File Access Attempts: Entering 8
            File Access Attempts: Entering 9
            File Access Attempts: Exiting 8
            File Access Attempts: Entering 9
            File Access Attempts: Entering 10
            File Access Attempts: Entering 11
            So the complexity of the likely answer is increasing. It seems if I'd like to maintain the benefit of multi-core optimisation then I'll need to learn about multi-thread file access management. I can take a look at that, but any helpful pointers in the right direction to get the process under way would be much appreciated, as it's new territory for me. But I expect that I'll not be the only one along the way who would like to get optimisation data out to files...........

            Thanks

            Riskybiz

            Comment


              #7
              >> I can take a look at that, but any helpful pointers in the right direction to get the process
              Sorry, I would not have any pointers at hand apart from consulting the Microsoft docs.

              Comment


                #8
                Riskybiz,

                I propose a 2-step-approach:
                1. Ensure, that you understand the current behaviour completely. Evalutate all posibilities which keep files open un-intended. Only if it is confirmed to be expected behaviour I would consider step #2.
                2. Apply Filestream() instead of StreamWriter().

                Regards
                Ralph

                Comment


                  #9
                  Problem Solved

                  I've managed to work around the issue of errors when writing to file during strategy optimisation (NT7 B14). The answer was to implement a Mutex class object on the WriteFile method.

                  A synchronization primitive that can also be used for interprocess synchronization.


                  The Mutex class is used in this case to control the file access requests from multiple optimisation threads. Only one thread may access the WriteFile at any one time (thus eliminating the 'file in use by another process' error I was receiving), other threads are paused until the prior thread has completed writing to file. This approach does appear to reduce the speed at which an optimisation runs, maybe there are better ways to code it, but at least by this means the data can now be put to file!

                  Here is the code;

                  Code:
                  #region Using declarations
                  using System;
                  using System.ComponentModel;
                  using System.Diagnostics;
                  using System.Drawing;
                  using System.Drawing.Drawing2D;
                  using System.Xml.Serialization;
                  using NinjaTrader.Cbi;
                  using NinjaTrader.Data;
                  using NinjaTrader.Indicator;
                  using NinjaTrader.Strategy;
                  using System.IO;
                  using System.Threading;
                  using System.Windows.Forms;
                  #endregion
                  
                  // This namespace holds all strategies and is required. Do not change it.
                  namespace NinjaTrader.Strategy
                  {
                  	/// <summary>
                  	/// Simple moving average cross over strategy.
                  	/// </summary>
                  	[Description("Simple moving average cross over strategy, with View360 Export code.")]
                  	public class SGMACrossOver : Strategy
                  	{
                  		#region Variables
                  		private int		fast	= 10;
                  		private int		slow	= 25;
                  		
                  		private bool view360Export = false;
                  		private static string optimisationFile;
                  		private bool performanceReport = false;
                  		private static string performanceReportFile;
                  		
                  		private string dateString;
                  		private string perfHeadString;
                  		private string perfString;
                  		private double np;
                  		private string instrument = "";
                  		
                  		private static DateTime timeStamp = DateTime.Now;// will only ever be one variable 'timeStamp', no matter how many class instances
                  		private static int accessCounter = 0;// will only ever be one variable 'accessCounter', no matter how many class instances
                  		private static Mutex mut = new Mutex(false, "NTWriteToFile");// will only ever be one variable 'mut', no matter how many class instances
                  		#endregion
                  
                  		/// <summary>
                  		/// This method is used to configure the strategy and is called once before any strategy method is called.
                  		/// </summary>
                  		protected override void Initialize()
                  		{
                  			SMA(Fast).Plots[0].Pen.Color = Color.Orange;
                  			SMA(Slow).Plots[0].Pen.Color = Color.Green;
                  
                  			Add(SMA(Fast));
                  			Add(SMA(Slow));
                  
                  			CalculateOnBarClose	= true;
                  		}
                  
                  		[Browsable(false)]
                  		public bool LastBarOnChart
                  		{
                  		 get
                  		 {
                  		 if (!CalculateOnBarClose && CurrentBar == Bars.Count - 1)
                  		 return true;
                  		 else if (CalculateOnBarClose && CurrentBar == Bars.Count - 2)
                  		 return true;
                  
                  		 return false;
                  		 }
                  		}
                  		
                  		private void WriteFile(string fileName, string line)
                  		{
                  		mut.WaitOne(); //wait until safe to enter; prior thread has completed writing.
                  		string file = fileName;		
                  		try
                  		 {
                  		  //accessCounter += 1;//increment
                  		  //Print("File Access Attempts: Entering " + accessCounter.ToString());
                  		 using (System.IO.StreamWriter writer = new System.IO.StreamWriter(file,true))//StreamWriter inside a using statement automatically calls Dispose()
                  		  {
                  		   writer.WriteLine(line);
                  			 
                  		   //accessCounter -= 1;//decrement
                  		   //Print("File Access Attempts: Exiting " + accessCounter.ToString());
                  		  }
                  		 mut.ReleaseMutex();//release the Mutex; to allow a different thread to use WriteFile
                  		 }//end try block
                  		 catch (System.Exception exp)
                  		  {
                  		  Log("File write error for file name '" + fileName + "' Error '" + exp.Message + "'", LogLevel.Warning);
                  		  }
                  		}
                  		
                  		
                  		//on bar update
                  		protected override void OnBarUpdate()
                  		{
                  		
                  		// strategy	
                  		 {
                  			if (CrossAbove(SMA(Fast), SMA(Slow), 1))
                  			    EnterLong();
                  			else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
                  			    EnterShort();
                  		 }
                  				
                  		try
                  		 {
                  		 //view360 export
                  		
                  		 if(view360Export == true && (optimisationFile == null || Instrument.FullName.ToString()!= instrument))//create filename if it doesn't exist already
                  		  {
                  		   dateString = timeStamp.ToString("yyyyMMdd Hmm");
                  			
                  		   optimisationFile = @"C:\Automation Data\" + dateString + "hrs " + Instrument.FullName.ToString() + " SGMACrossover View360 Data.csv";
                  		   instrument = Instrument.FullName.ToString();
                  		  }	
                  			
                  	     if (Performance.AllTrades.Count > 0 && CurrentBar == Bars.Count-2 && view360Export == true)
                  		  {
                  		   for (int i = 0; i < Performance.AllTrades.Count; i++)
                  		    {
                  			Trade lastTrade = Performance.AllTrades[i];
                  			double lastProfit = lastTrade.ProfitCurrency *
                  			lastTrade.Quantity;
                  			lastProfit = Math.Round(lastProfit,2);
                  			int MP = 0;
                  		
                  		   if (lastTrade.Entry.MarketPosition == MarketPosition.Short)
                  		   {
                  		    MP = -1;
                  		   }
                  		   else if (lastTrade.Entry.MarketPosition == MarketPosition.Long)
                  		    {
                  			 MP = 1;
                  		    }
                  		
                          string input1 = fast.ToString();
                  		string input2 = slow.ToString();
                  		string input3 = " ";
                  		string input4 = " ";
                  		string input5 = " ";
                  		string input6 = " ";
                  		string input7 = " ";
                  		string input8 = " ";
                  		string input9 = " ";
                  		string input10 = " ";
                  		
                  		WriteFile(optimisationFile, lastTrade.Entry.Instrument.ToString() + "," +
                  		input1 + "," + input2 + "," + input3 + "," +
                  		input4 + "," + input5 + "," + input6 + "," +
                  		input7 + "," + input8 + "," + input9 + "," +
                  		input10 + "," + lastTrade.Quantity.ToString() +
                  		"," + MP.ToString() + "," +
                  		lastTrade.Entry.Time.ToShortDateString() + "," +
                  		lastTrade.Entry.Price.ToString() + "," +
                  		lastTrade.Exit.Time.ToShortDateString() + "," +
                  		lastTrade.Exit.Price.ToString() + "," +
                  		lastProfit.ToString());
                  		}
                  		}
                  	}//end view360report
                  	catch (Exception e)
                  	 {
                  		Log("Error: View 360 Export Code Error" , NinjaTrader.Cbi.LogLevel.Error);
                  		throw(e);
                       }
                  	
                  	//performance report
                  	try
                  	{
                  	if(LastBarOnChart == true && performanceReport == true)
                  	 {
                  				
                  		if(performanceReportFile == null)//create filename if it doesn't exist already
                  		{
                  			dateString = timeStamp.ToString("yyyyMMdd Hmm");
                  			
                  			performanceReportFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover Optimisation Performance Summary.csv";
                  			perfHeadString = "Instrument Name, Fast MA, Slow MA, NetProfit";
                  			WriteFile(performanceReportFile, perfHeadString);
                  		}
                  				
                  		np = (Performance.AllTrades.TradesPerformance.GrossProfit - Performance.AllTrades.TradesPerformance.GrossLoss);
                  		
                  		perfString = Instrument.FullName + "," + fast.ToString() + "," + slow.ToString() + "," + np.ToString();
                  		WriteFile(performanceReportFile, perfString);
                  				
                  	 }//end performance report
                  	}//end try block
                  	catch (Exception e)
                  	 {
                  		Log("Error: Optimisation Performance Report Error" , NinjaTrader.Cbi.LogLevel.Error);
                  		throw(e);
                       }//catch
                  	
                  	
                  }//on bar update	
                  
                  		
                  		#region Properties
                  		/// <summary>
                  		/// </summary>
                  		[Description("Period for fast MA")]
                  		[Category("Parameters")]
                  		public int Fast
                  		{
                  			get { return fast; }
                  			set { fast = Math.Max(1, value); }
                  		}
                  
                  		/// <summary>
                  		/// </summary>
                  		[Description("Period for slow MA")]
                  		[Category("Parameters")]
                  		public int Slow
                  		{
                  			get { return slow; }
                  			set { slow = Math.Max(1, value); }
                  		}
                  		//View360 addition
                  		[Description("Enable View360 Data Export; Use During Optimisations")]
                  		[Category("Parameters")]
                  		public bool Export_View360_Report
                  		{
                  		get { return view360Export; }
                  		set { view360Export = value; }
                  		}
                  		
                  		//Performance Summary
                  		[Description("Enable Performance Summary Report; Use During Optimisations")]
                  		[Category("Parameters")]
                  		public bool Export_Performance_Summary
                  		{
                  		get { return performanceReport; }
                  		set { performanceReport = value; }
                  		}
                  		
                  		//File Date & Time Stamp
                  		[ReadOnlyAttribute(true)]
                  		[Description("Date & Time Stamp For Output Files")]
                  		[Category("Parameters")]
                  		public DateTime Time_Stamp
                  		{
                  		get { return timeStamp; }
                  		set { timeStamp = value; }
                  		}
                  		
                  		#endregion
                  	}
                  }

                  Comment


                    #10
                    Riskybiz, thank you for posting the final solution to this problem. I am sure others will find this information useful.
                    AustinNinjaTrader Customer Service

                    Comment


                      #11
                      Originally posted by Riskybiz View Post
                      ...maybe there are better ways to code it...
                      That depends on the appearance of the text lines written into the concerning file. If you want to have the text from one process atomic and not interruptes by text from other processes, then your solution looks like a good approach. If not (in case the order of written text lines doesn't matter), then you could enable multi process file stream access.

                      Regards
                      Ralph

                      Comment


                        #12
                        Recovered Optimisation Performance Speed

                        Thanks Ralph, yes I think for now I'll keep the lines in the right order! Might save confusion down the line........But will certainly hold your FileStream suggestion in mind for other projects.

                        This is just a quick note that by accumulating (pseudo buffering?) the lineout text into an ever expanding string variable then dumping it to file on the final bar of the chart, rather than writing repeatedly throughout the optimisation run I have managed to regain the speed / performance of the optimisation. In tests without 'buffering' my test optimisation run took roughly 50 seconds, with the change to buffering the time taken dropped back to about 10 seconds (just a little slower than the strategy unencumbered by the file exports).

                        Revised code, in case it's of help to anyone.

                        Code:
                        #region Using declarations
                        using System;
                        using System.ComponentModel;
                        using System.Diagnostics;
                        using System.Drawing;
                        using System.Drawing.Drawing2D;
                        using System.Xml.Serialization;
                        using NinjaTrader.Cbi;
                        using NinjaTrader.Data;
                        using NinjaTrader.Indicator;
                        using NinjaTrader.Strategy;
                        using System.IO;
                        using System.Threading;
                        using System.Windows.Forms;
                        #endregion
                        
                        // This namespace holds all strategies and is required. Do not change it.
                        namespace NinjaTrader.Strategy
                        {
                        	/// <summary>
                        	/// Simple moving average cross over strategy.
                        	/// </summary>
                        	[Description("Simple moving average cross over strategy, with View360 Export code.")]
                        	public class SGMACrossOver : Strategy
                        	{
                        		#region Variables
                        		private int		fast	= 10;
                        		private int		slow	= 25;
                        		
                        		private bool view360Export = false;
                        		private static string optimisationFile;
                        		private bool performanceReport = false;
                        		private static string performanceReportFile;
                        		
                        		private string dateString;
                        		private string perfHeadString;
                        		private string perfString;
                        		private double np;
                        		private string instrument = "";
                        		
                        		private static DateTime timeStamp;// will only ever be one variable 'timeStamp', no matter how many class instances
                        		private static int accessCounter = 0;// will only ever be one variable 'accessCounter', no matter how many class instances
                        		private static Mutex mut = new Mutex(false, "NTWriteToFile");// will only ever be one variable 'mut', no matter how many class instances
                        		private static bool reset;
                        		private string buffer;
                        		#endregion
                        
                        		/// <summary>
                        		/// This method is used to configure the strategy and is called once before any strategy method is called.
                        		/// </summary>
                        		protected override void Initialize()
                        		{
                        			SMA(Fast).Plots[0].Pen.Color = Color.Orange;
                        			SMA(Slow).Plots[0].Pen.Color = Color.Green;
                        
                        			Add(SMA(Fast));
                        			Add(SMA(Slow));
                        
                        			CalculateOnBarClose	= true;
                        			
                        			
                        		}
                        
                        		[Browsable(false)]
                        		public bool LastBarOnChart
                        		{
                        		 get
                        		 {
                        		 if (!CalculateOnBarClose && CurrentBar == Bars.Count - 1)
                        		 return true;
                        		 else if (CalculateOnBarClose && CurrentBar == Bars.Count - 2)
                        		 return true;
                        
                        		 return false;
                        		 }
                        		}
                        		
                        		private void WriteFile(string fileName, string line)
                        		{
                        		mut.WaitOne(); //wait until safe to enter; prior thread has completed writing.
                        		string file = fileName;	
                        		try
                        		 {
                        		  //accessCounter += 1;//increment
                        		  //Print("File Access Attempts: Entering " + accessCounter.ToString());
                        		 using (System.IO.StreamWriter writer = new System.IO.StreamWriter(file,true))//StreamWriter inside a using statement automatically calls Dispose()
                        		  {
                        		   writer.WriteLine(line);
                        			 
                        		   //accessCounter -= 1;//decrement
                        		   //Print("File Access Attempts: Exiting " + accessCounter.ToString());
                        		  }
                        		 mut.ReleaseMutex();//release the Mutex; to allow a different thread to use WriteFile
                        		 }//end try block
                        		 catch (System.Exception exp)
                        		  {
                        		  Log("File write error for file name '" + fileName + "' Error '" + exp.Message + "'", LogLevel.Warning);
                        		  }
                        		}
                        		
                        		protected override void OnStartUp()
                        		{
                             		if(reset == true)
                        			{
                        				timeStamp = DateTime.Now;
                        				reset = false;
                        			}
                        		}
                        				
                        		
                        		//on bar update
                        		protected override void OnBarUpdate()
                        		{
                        		if(timeStamp == DateTime.MinValue)
                        			{
                        				timeStamp = DateTime.Now;
                        			}
                        		// strategy	
                        		 {
                        			if (CrossAbove(SMA(Fast), SMA(Slow), 1))
                        			    EnterLong();
                        			else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
                        			    EnterShort();
                        		 }
                        				
                        		try
                        		 {
                        		 //view360 export
                        		
                        		 if(view360Export == true && (optimisationFile == null || Instrument.FullName.ToString()!= instrument))//create filename if it doesn't exist already
                        		  {
                        		   dateString = timeStamp.ToString("yyyyMMdd Hmm");
                        		   optimisationFile = @"C:\Automation Data\" + dateString + "hrs " + Instrument.FullName.ToString() + " SGMACrossover View360 Data.csv";
                        		   instrument = Instrument.FullName.ToString();
                        		  }	
                        			
                        	     if (Performance.AllTrades.Count > 0 && CurrentBar == Bars.Count-2 && view360Export == true)
                        		  {
                        		   	for (int i = 0; i < Performance.AllTrades.Count; i++)
                        		    {
                        			Trade lastTrade = Performance.AllTrades[i];
                        			double lastProfit = lastTrade.ProfitCurrency *
                        			lastTrade.Quantity;
                        			lastProfit = Math.Round(lastProfit,2);
                        			int MP = 0;
                        		
                        		   if (lastTrade.Entry.MarketPosition == MarketPosition.Short)
                        		   {
                        		    MP = -1;
                        		   }
                        		   else if (lastTrade.Entry.MarketPosition == MarketPosition.Long)
                        		    {
                        			 MP = 1;
                        		    }
                        		
                                string input1 = fast.ToString();
                        		string input2 = slow.ToString();
                        		string input3 = " ";
                        		string input4 = " ";
                        		string input5 = " ";
                        		string input6 = " ";
                        		string input7 = " ";
                        		string input8 = " ";
                        		string input9 = " ";
                        		string input10 = " ";
                        		
                        		buffer += lastTrade.Entry.Instrument.FullName.ToString() + "," +
                        		input1 + "," + input2 + "," + input3 + "," +
                        		input4 + "," + input5 + "," + input6 + "," +
                        		input7 + "," + input8 + "," + input9 + "," +
                        		input10 + "," + lastTrade.Quantity.ToString() +
                        		"," + MP.ToString() + "," +
                        		lastTrade.Entry.Time.ToShortDateString() + "," +
                        		lastTrade.Entry.Price.ToString() + "," +
                        		lastTrade.Exit.Time.ToShortDateString() + "," +
                        		lastTrade.Exit.Price.ToString() + "," +
                        		lastProfit.ToString("F4") + "\n";
                        		
                        		}//end loop
                        		
                        		if(LastBarOnChart == true)
                        		{
                        		 WriteFile(optimisationFile, buffer);
                        		 buffer = "";
                        		}
                        		}//end if
                        	}//end view360report
                        	catch (Exception e)
                        	 {
                        		Log("Error: View 360 Export Code Error" , NinjaTrader.Cbi.LogLevel.Error);
                        		throw(e);
                             }
                        	
                        	//performance report
                        	try
                        	{
                        	if(LastBarOnChart == true && performanceReport == true)
                        	 {
                        				
                        		if(performanceReportFile == null)//create filename if it doesn't exist already
                        		{
                        			dateString = timeStamp.ToString("yyyyMMdd Hmm");
                        			
                        			performanceReportFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover Optimisation Performance Summary.csv";
                        			perfHeadString = "Instrument Name, Fast MA, Slow MA, NetProfit";
                        			WriteFile(performanceReportFile, perfHeadString);
                        		}
                        				
                        		np = (Performance.AllTrades.TradesPerformance.GrossProfit - Performance.AllTrades.TradesPerformance.GrossLoss);
                        		
                        		perfString = Instrument.FullName + "," + fast.ToString() + "," + slow.ToString() + "," + np.ToString();
                        		WriteFile(performanceReportFile, perfString);
                        				
                        	 }//end performance report
                        	}//end try block
                        	catch (Exception e)
                        	 {
                        		Log("Error: Optimisation Performance Report Error" , NinjaTrader.Cbi.LogLevel.Error);
                        		throw(e);
                             }//catch
                        	
                        	
                        }//on bar update	
                        
                        		
                        		#region Properties
                        		/// <summary>
                        		/// </summary>
                        		[Description("Period for fast MA")]
                        		[Category("Parameters")]
                        		public int Fast
                        		{
                        			get { return fast; }
                        			set { fast = Math.Max(1, value); }
                        		}
                        
                        		/// <summary>
                        		/// </summary>
                        		[Description("Period for slow MA")]
                        		[Category("Parameters")]
                        		public int Slow
                        		{
                        			get { return slow; }
                        			set { slow = Math.Max(1, value); }
                        		}
                        		//View360 addition
                        		[Description("Enable View360 Data Export; Use During Optimisations")]
                        		[Category("Parameters")]
                        		public bool Export_View360_Report
                        		{
                        		get { return view360Export; }
                        		set { view360Export = value; }
                        		}
                        		
                        		//Performance Summary
                        		[Description("Enable Performance Summary Report; Use During Optimisations")]
                        		[Category("Parameters")]
                        		public bool Export_Performance_Summary
                        		{
                        		get { return performanceReport; }
                        		set { performanceReport = value; }
                        		}
                        		
                        		//File Date & Time Stamp
                        		[Description("Reset Date And Time Stamp For Output Files; Important to Prevent Overwriting")]
                        		[Category("Parameters")]
                        		public bool Reset_Time_Stamp
                        		{
                        		get { return reset; }
                        		set { reset = value; }
                        		}
                        		
                        		#endregion
                        	}
                        }

                        Comment


                          #13
                          Great piece of code Riskybiz!
                          I think you don't need a check for when the strategy is done, you could move your mutex-filestream operation into the Dispose() method.

                          Regards
                          Ralph

                          Comment


                            #14
                            Corrected Issue in View360 Export Data Format

                            Just for completeness..........The prior code I posted was erroneously inserting occasional blank lines into the View360 report, this would cause that software to not read the file properly. I've corrected this now.

                            Code:
                            #region Using declarations
                            using System;
                            using System.ComponentModel;
                            using System.Diagnostics;
                            using System.Drawing;
                            using System.Drawing.Drawing2D;
                            using System.Xml.Serialization;
                            using NinjaTrader.Cbi;
                            using NinjaTrader.Data;
                            using NinjaTrader.Indicator;
                            using NinjaTrader.Strategy;
                            using System.IO;
                            using System.Threading;
                            using System.Windows.Forms;
                            #endregion
                            
                            // This namespace holds all strategies and is required. Do not change it.
                            namespace NinjaTrader.Strategy
                            {
                            	/// <summary>
                            	/// Simple moving average cross over strategy.
                            	/// </summary>
                            	[Description("Simple moving average cross over strategy, with View360 Export code.")]
                            	public class SGMACrossOver : Strategy
                            	{
                            		#region Variables
                            		private int		fast	= 10;
                            		private int		slow	= 25;
                            		
                            		private bool view360Export = false;
                            		private string optimisationFile;
                            		private bool performanceReport = false;
                            		private static string performanceReportFile;//static as multiple threads/instances will refer to the assigned value
                            		
                            		private string dateString;
                            		private string perfHeadString;
                            		private string perfString;
                            		private double np;
                            		private string instrument = "";
                            		
                            		private static DateTime timeStamp;
                            		private static int accessCounter = 0;
                            		private static Mutex mut = new Mutex(false, "NTWriteToFile");
                            		private static bool reset;
                            		private string buffer;
                            		
                            		private string trimmedBuffer;
                            		
                            		#endregion
                            
                            		/// <summary>
                            		/// This method is used to configure the strategy and is called once before any strategy method is called.
                            		/// </summary>
                            		protected override void Initialize()
                            		{
                            			SMA(Fast).Plots[0].Pen.Color = Color.Orange;
                            			SMA(Slow).Plots[0].Pen.Color = Color.Green;
                            
                            			Add(SMA(Fast));
                            			Add(SMA(Slow));
                            
                            			CalculateOnBarClose	= true;
                            			
                            			
                            		}
                            
                            		[Browsable(false)]
                            		public bool LastBarOnChart
                            		{
                            		 get
                            		 {
                            		 if (!CalculateOnBarClose && CurrentBar == Bars.Count - 1)
                            		 return true;
                            		 else if (CalculateOnBarClose && CurrentBar == Bars.Count - 2)
                            		 return true;
                            
                            		 return false;
                            		 }
                            		}
                            		
                            		private void WriteFile(string fileName, string line)
                            		{
                            		mut.WaitOne(); //wait until safe to enter; prior thread has completed writing.
                            		string file = fileName;	
                            		try
                            		 {
                            		  //accessCounter += 1;//increment
                            		  //Print("File Access Attempts: Entering " + accessCounter.ToString());
                            		 using (System.IO.StreamWriter writer = new System.IO.StreamWriter(file,true))//StreamWriter inside a using statement automatically calls Dispose()
                            		  {
                            		   writer.WriteLine(line);		 
                            		   //accessCounter -= 1;//decrement
                            		   //Print("File Access Attempts: Exiting " + accessCounter.ToString());
                            		  }
                            		 mut.ReleaseMutex();//release the Mutex; to allow a different thread to use WriteFile
                            		 }//end try block
                            		 catch (System.Exception exp)
                            		  {
                            		  Log("File write error for file name '" + fileName + "' Error '" + exp.Message + "'", LogLevel.Warning);
                            		  }
                            		}
                            		
                            		protected override void OnStartUp()//set the Date & Time Stamp used in naming output files
                            		{
                                 		if(reset == true)
                            			{
                            				timeStamp = DateTime.Now;
                            				reset = false;
                            			}
                            			else if(timeStamp == DateTime.MinValue)
                            			{
                            				timeStamp = DateTime.Now;
                            			}
                            		}
                            		
                            				
                            		//on bar update
                            		protected override void OnBarUpdate()
                            		{
                            		// strategy	
                            		 {
                            			if (CrossAbove(SMA(Fast), SMA(Slow), 1))
                            			    EnterLong();
                            			else if (CrossBelow(SMA(Fast), SMA(Slow), 1))
                            			    EnterShort();
                            		 }
                            				
                            		try
                            		 {
                            		 //view360 export
                            		if(view360Export == true && (optimisationFile == null))//set filename
                            		  {
                            		   dateString = timeStamp.ToString("yyyyMMdd HHmm");
                            		   instrument = Instrument.FullName.ToString();
                            		   optimisationFile = @"C:\Automation Data\" + dateString + "hrs " + instrument + " SGMACrossover View360 Data.csv";
                            		  }	
                            			
                            	     if (Performance.AllTrades.Count > 0 && CurrentBar == Bars.Count-2 && view360Export == true)
                            		  {
                            		   	for (int i = 0; i < Performance.AllTrades.Count; i++)
                            		    {
                            			Trade lastTrade = Performance.AllTrades[i];
                            			double lastProfit = lastTrade.ProfitCurrency *
                            			lastTrade.Quantity;
                            			lastProfit = Math.Round(lastProfit,2);
                            			int MP = 0;
                            		
                            		   if (lastTrade.Entry.MarketPosition == MarketPosition.Short)
                            		   {
                            		    MP = -1;
                            		   }
                            		   else if (lastTrade.Entry.MarketPosition == MarketPosition.Long)
                            		    {
                            			 MP = 1;
                            		    }
                            		
                                    string input1 = fast.ToString();
                            		string input2 = slow.ToString();
                            		string input3 = " ";
                            		string input4 = " ";
                            		string input5 = " ";
                            		string input6 = " ";
                            		string input7 = " ";
                            		string input8 = " ";
                            		string input9 = " ";
                            		string input10 = " ";
                            		
                            		buffer += lastTrade.Entry.Instrument.FullName.ToString() + "," +
                            		input1 + "," + input2 + "," + input3 + "," +
                            		input4 + "," + input5 + "," + input6 + "," +
                            		input7 + "," + input8 + "," + input9 + "," +
                            		input10 + "," + lastTrade.Quantity.ToString() +
                            		"," + MP.ToString() + "," +
                            		lastTrade.Entry.Time.ToShortDateString() + "," +
                            		lastTrade.Entry.Price.ToString() + "," +
                            		lastTrade.Exit.Time.ToShortDateString() + "," +
                            		lastTrade.Exit.Price.ToString() + "," +
                            		lastProfit.ToString() + "\n";
                            		
                            		}//end loop
                            		
                            		if(LastBarOnChart == true)
                            		{
                            		 char[] trimChar = {'\n',' '};
                            		 trimmedBuffer = buffer.TrimEnd(trimChar);//remove final newline character
                            		 buffer = "";//reset
                            		 WriteFile(optimisationFile, trimmedBuffer);
                            		 trimmedBuffer = "";//reset
                            		}
                            		}//end if
                            	}//end view360report
                            	catch (Exception e)
                            	 {
                            		Log("Error: View 360 Export Code Error" , NinjaTrader.Cbi.LogLevel.Error);
                            		throw(e);
                                 }
                            	
                            	//performance report
                            	try
                            	{
                            	if(LastBarOnChart == true && performanceReport == true)
                            	 {
                            				
                            		if(performanceReportFile == null)//create filename if it doesn't exist already
                            		{
                            			dateString = timeStamp.ToString("yyyyMMdd HHmm");
                            			
                            			performanceReportFile = @"C:\Automation Data\" + dateString + "hrs SGMACrossover Optimisation Performance Summary.csv";
                            			perfHeadString = "Instrument Name, Fast MA, Slow MA, NetProfit";
                            			WriteFile(performanceReportFile, perfHeadString);
                            		}
                            				
                            		np = (Performance.AllTrades.TradesPerformance.GrossProfit - Performance.AllTrades.TradesPerformance.GrossLoss);
                            		
                            		perfString = Instrument.FullName + "," + fast.ToString() + "," + slow.ToString() + "," + np.ToString();
                            		WriteFile(performanceReportFile, perfString);
                            				
                            	 }//end performance report
                            	}//end try block
                            	catch (Exception e)
                            	 {
                            		Log("Error: Optimisation Performance Report Error" , NinjaTrader.Cbi.LogLevel.Error);
                            		throw(e);
                                 }//catch
                            	
                            	
                            }//on bar update	
                            
                            		
                            		#region Properties
                            		/// <summary>
                            		/// </summary>
                            		[Description("Period for fast MA")]
                            		[Category("Parameters")]
                            		public int Fast
                            		{
                            			get { return fast; }
                            			set { fast = Math.Max(1, value); }
                            		}
                            
                            		/// <summary>
                            		/// </summary>
                            		[Description("Period for slow MA")]
                            		[Category("Parameters")]
                            		public int Slow
                            		{
                            			get { return slow; }
                            			set { slow = Math.Max(1, value); }
                            		}
                            		//View360 addition
                            		[Description("Enable View360 Data Export; Use During Optimisations")]
                            		[Category("Parameters")]
                            		public bool Export_View360_Report
                            		{
                            		get { return view360Export; }
                            		set { view360Export = value; }
                            		}
                            		
                            		//Performance Summary
                            		[Description("Enable Performance Summary Report; Use During Optimisations")]
                            		[Category("Parameters")]
                            		public bool Export_Performance_Summary
                            		{
                            		get { return performanceReport; }
                            		set { performanceReport = value; }
                            		}
                            		
                            		//File Date & Time Stamp
                            		[Description("Reset Date And Time Stamp For Output Files; Important to Prevent Overwriting")]
                            		[Category("Parameters")]
                            		public bool Reset_Time_Stamp
                            		{
                            		get { return reset; }
                            		set { reset = value; }
                            		}
                            		
                            		#endregion
                            	}
                            }
                            Last edited by Riskybiz; 04-22-2010, 06:49 AM. Reason: Adjusted Code

                            Comment


                              #15
                              lock ?

                              Just wondering if all you need do is to use lock to block while a thread uses the write file proc...?

                              Use the C# lock statement to ensure that only a single thread exclusively reads or writes a shared resource, blocking all other threads until it completes.


                              Object thisLock = new Object();
                              lock (thisLock)
                              {
                              // Critical code section.
                              }

                              works for when you have multiple threads accessing a code block - where perhaps one is still perhaps writing to a file etc - or connecting etc- within the same application

                              Nice mutex example BTW :-)
                              Last edited by MicroTrends; 04-23-2010, 02:23 PM.
                              MicroTrends
                              NinjaTrader Ecosystem Vendor - micro-trends.co.uk

                              Comment

                              Latest Posts

                              Collapse

                              Topics Statistics Last Post
                              Started by XXtrader, Yesterday, 11:30 PM
                              2 responses
                              11 views
                              0 likes
                              Last Post XXtrader  
                              Started by Waxavi, Today, 02:10 AM
                              0 responses
                              6 views
                              0 likes
                              Last Post Waxavi
                              by Waxavi
                               
                              Started by TradeForge, Today, 02:09 AM
                              0 responses
                              11 views
                              0 likes
                              Last Post TradeForge  
                              Started by Waxavi, Today, 02:00 AM
                              0 responses
                              2 views
                              0 likes
                              Last Post Waxavi
                              by Waxavi
                               
                              Started by elirion, Today, 01:36 AM
                              0 responses
                              7 views
                              0 likes
                              Last Post elirion
                              by elirion
                               
                              Working...
                              X