/// <summary> /// Reads the specified data streams, and converts them into a basic stock data file /// </summary> /// <param name="sourceFiles">The legacy data files</param> /// <returns>The new data file</returns> public static StockDataFile Convert(List <string> sourceFiles, Stream destination) { StockDataFile newFile = new StockDataFile(); newFile.Interval = new TimeSpan(0, 1, 0); Dictionary <string, List <StockDataSet <StockDataBase> > > segments = new Dictionary <string, List <StockDataSet <StockDataBase> > >(); foreach (string filename in sourceFiles) { // Parse the date from the filename DateTime fileDate = GetDateFromFileName(filename); DateTime fileStart = fileDate.AddHours(9.5); DateTime fileEnd = fileDate.AddHours(16); long delayedOffset = (filename.Contains("goog")) ? 0 : new TimeSpan(0, 15, 0).Ticks; // Read the initial line of the file to learn which stocks are in the file StreamReader s = new StreamReader(filename); List <StockDataSet <StockDataBase> > fileData = new List <StockDataSet <StockDataBase> >(); string line = s.ReadLine(); string[] stockNamesStr = line.Split(new char[] { ',' }); for (int i = 1; i < stockNamesStr.Length; i++) { string symbol = stockNamesStr[i].ToUpper(); List <StockDataSet <StockDataBase> > sets; // Check if a stock data set already exists for the symbol if (!segments.TryGetValue(symbol, out sets)) { sets = new List <StockDataSet <StockDataBase> >(); segments.Add(symbol, sets); } foreach (StockDataSet <StockDataBase> preExistingSet in sets) { // Add to an existing set if they are for the same day if (preExistingSet.Start.Date == fileStart.Date) { fileData.Add(preExistingSet); break; } } if (fileData.Count <= (i - 1)) { // No matching set was found, so create a new one StockDataSet <StockDataBase> newSet = new StockDataSet <StockDataBase>(symbol, fileStart, newFile); newSet.DataSet.Resize(391); fileData.Add(newSet); if (sets.Count > 0) { newSet.Previous = sets[sets.Count - 1]; } sets.Add(newSet); } } DateTime lineTime = fileStart; while (!s.EndOfStream && (lineTime < fileEnd)) { string[] stockPricesStr = s.ReadLine().Split(new char[] { ',' }); // Ensure the entry contains all of the stocks if ((stockPricesStr.Length - 1) != fileData.Count) { continue; } // Get the time of the entry DateTime newTime; if (!DateTime.TryParse(stockPricesStr[0].Replace("\"", ""), out newTime)) { continue; } newTime = fileStart.AddTicks((newTime.TimeOfDay.Ticks - fileStart.TimeOfDay.Ticks) - delayedOffset); // Check if this new entry is valid if ((newTime >= fileStart) && (newTime <= fileEnd)) { // Update the prices of each of the stocks for (int i = 0; i < (stockPricesStr.Length - 1); i++) { float price; if (float.TryParse(stockPricesStr[i + 1], out price)) { // Sometimes the first price is corrupted, so skip it if ((newTime == fileStart) //&& ((fileData[i].Previous != null) && (Math.Abs((price / fileData[i][-1].Price) - 1.0f) > 0.01f)) ) { continue; } if ((price == 0.0f) || (newTime == fileEnd)) { price = fileData[i][fileData[i].Count - 1].Price; if (price == 0.0f) { continue; } } while (fileData[i].End <= newTime) { fileData[i].DataSet.Add(new StockDataBase(price)); } } } } } } // Save the old file to disk newFile.SetSegments(segments); newFile.Save(destination, typeof(StockDataBase), segments); return(newFile); }
public void Run() { System.Windows.Forms.OpenFileDialog diag = new System.Windows.Forms.OpenFileDialog(); diag.Multiselect = true; diag.Title = "Open Stock Data File..."; if (diag.ShowDialog() == System.Windows.Forms.DialogResult.OK) { List <string> script = new List <string>(); Directory.CreateDirectory("tmp"); // Get the source file if (diag.FileName.EndsWith(".csv")) { System.Windows.Forms.SaveFileDialog saveDiag = new System.Windows.Forms.SaveFileDialog(); if (saveDiag.ShowDialog() != System.Windows.Forms.DialogResult.OK) { return; } SourceFile = StockDataFile.Convert(diag.FileNames.ToList(), new FileStream(saveDiag.FileName, FileMode.Create)); } else { SourceFile = StockDataFile.Open(new FileStream(diag.FileName, FileMode.Open)); } script.Add("tmp/" + SOURCE_CLASS + ".cs"); using (var file = new StreamWriter(new FileStream(script.Last(), FileMode.Create))) file.Write(SourceFile.GetSourceCode(SOURCE_CLASS)); // Create the sink file //SinkFile = new StockDataFile(new List<string>() { }, new List<string>() { }); SinkFile = new StockDataFile(new List <string>() { "MovingAverage" }, new List <string>() { File.ReadAllText(@"Script/Data/MovingAverage.cs") }); script.Add("tmp/" + SINK_CLASS + ".cs"); using (var file = new StreamWriter(new FileStream(script.Last(), FileMode.Create))) file.Write(SinkFile.GetSourceCode(SINK_CLASS)); // Create the analyzer file (needs to be compiled in the script since it references StockDataSource) var analyzerFilename = "RobinhoodDesktop.Script.StockAnalyzer.cs"; script.Add("tmp/StockAnalyzer.cs"); StringBuilder analyzerCode = new StringBuilder(); analyzerCode.Append(new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(analyzerFilename)).ReadToEnd()); using (var file = new StreamWriter(new FileStream(script.Last(), FileMode.Create))) file.Write(StockDataFile.FormatSource(analyzerCode.ToString())); // Add the user defined analyzers string[] analyzerPaths = Directory.GetFiles(@"Script/Decision", "*.cs", SearchOption.AllDirectories); foreach (string path in analyzerPaths) { script.Add(path); } // Get the code that will actually run the session script.Add("tmp/StockSessionScript.cs"); var sessionFilename = "RobinhoodDesktop.Script.StockSessionScript.cs"; using (var file = new StreamWriter(new FileStream(script.Last(), FileMode.Create))) file.Write(new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream(sessionFilename)).ReadToEnd()); // Build and run the session #if DEBUG var isDebug = true; #else var isDebug = false; #endif #if true try { var scriptInstance = CSScript.LoadFiles(script.ToArray(), null, isDebug); var run = scriptInstance.GetStaticMethod("RobinhoodDesktop.Script.StockSessionScript.Run", this); run(this); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.ToString()); } #else // Set up the derived data sink var sourceData = SourceFile.GetSegments <StockDataBase>(); var sinkData = StockDataSetDerived <StockDataBase, StockDataBase> .Derive(sourceData, SinkFile, (data, idx) => { var point = new StockDataBase(); point.Update(data, idx); return(point); }); SinkFile.SetSegments(sinkData); // Load the first set of data foreach (var pair in sinkData) { foreach (var set in pair.Value) { set.Load(); } } #endif // Cleanup SourceFile.Close(); } }