/* * QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. * Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.IO; using System.Linq; using QuantConnect.Util; using static QuantConnect.StringExtensions; namespace QuantConnect.ToolBox.QuantQuoteConverter { public static class QuantQuoteConverterProgram { /// /// Primary entry point to the program /// public static void QuantQuoteConverter(string destinationDirectory, string sourceDirectory, string resolution) { //Document the process: Console.WriteLine("QuantConnect.ToolBox: QuantQuote Converter: "); Console.WriteLine("=============================================="); Console.WriteLine("The QuantQuote converter transforms QuantQuote orders into the LEAN Algorithmic Trading Engine Data Format."); Console.WriteLine("Parameters required: --source-dir= --destination-dir= --resolution="); Console.WriteLine(" 1> Source Directory of Unzipped QuantQuote Data."); Console.WriteLine(" 2> Destination Directory of LEAN Data Folder. (Typically located under Lean/Data)"); Console.WriteLine(" 3> Resolution of your QuantQuote data. (either minute, second or tick)"); Console.WriteLine(" "); Console.WriteLine("NOTE: THIS WILL OVERWRITE ANY EXISTING FILES."); if(sourceDirectory.IsNullOrEmpty() || destinationDirectory.IsNullOrEmpty() || resolution.IsNullOrEmpty()) { Console.WriteLine("1. Source QuantQuote source directory: "); sourceDirectory = (Console.ReadLine() ?? ""); Console.WriteLine("2. Destination LEAN Data directory: "); destinationDirectory = (Console.ReadLine() ?? ""); Console.WriteLine("3. Enter Resolution (minute/second/tick): "); resolution = (Console.ReadLine() ?? ""); resolution = resolution.ToLowerInvariant(); } //Validate the user input: Validate(sourceDirectory, destinationDirectory, resolution); //Remove the final slash to make the path building easier: sourceDirectory = StripFinalSlash(sourceDirectory); destinationDirectory = StripFinalSlash(destinationDirectory); //Count the total files to process: Console.WriteLine("Counting Files..."); var count = 0; var totalCount = GetCount(sourceDirectory); Console.WriteLine(Invariant($"Processing {totalCount} Files ...")); //Enumerate files foreach (var directory in Directory.EnumerateDirectories(sourceDirectory)) { var date = GetDate(directory); foreach (var file in Directory.EnumerateFiles(directory)) { var symbol = GetSymbol(file); var fileContents = File.ReadAllText(file); var data = new Dictionary { { Invariant($"{date:yyyyMMdd}_{symbol}_Trade_Second.csv"), fileContents } }; var fileDestination = Invariant($"{destinationDirectory}/equity/{resolution}/{symbol}/{date:yyyyMMdd}_trade.zip"); if (!Compression.ZipData(fileDestination, data)) { Error("Error: Could not convert to Lean zip file."); } else { Console.WriteLine(Invariant($"Successfully processed {count} of {totalCount} files: {fileDestination}")); } count++; } } Console.ReadKey(); } /// /// Application error: display error and then stop conversion /// /// Error string private static void Error(string error) { Console.WriteLine(error); Console.ReadKey(); Environment.Exit(0); } /// /// Get the count of the files to process /// /// /// private static int GetCount(string sourceDirectory) { var count = 0; foreach (var directory in Directory.EnumerateDirectories(sourceDirectory)) { count += Directory.EnumerateFiles(directory, "*.csv").Count(); } return count; } /// /// Remove the final slash to make path building easier /// private static string StripFinalSlash(string directory) { return directory.Trim('/', '\\'); } /// /// Get the date component of tie file path. /// /// /// private static DateTime GetDate(string date) { var splits = date.Split('/', '\\'); var dateString = splits[splits.Length - 1].Replace("allstocks_", ""); return Parse.DateTimeExact(dateString, "yyyyMMdd"); } /// /// Extract the symbol from the path /// private static string GetSymbol(string filePath) { var splits = filePath.Split('/', '\\'); var file = splits[splits.Length - 1]; file = file.Trim( '.', '/', '\\'); file = file.Replace("table_", ""); return file.Replace(".csv", ""); } /// /// Validate the users input and throw error if not valid /// private static void Validate(string sourceDirectory, string destinationDirectory, string resolution) { if (string.IsNullOrWhiteSpace(sourceDirectory)) { Error("Error: Please enter a valid source directory."); } if (string.IsNullOrWhiteSpace(destinationDirectory)) { Error("Error: Please enter a valid destination directory."); } if (!Directory.Exists(sourceDirectory)) { Error("Error: Source directory does not exist."); } if (!Directory.Exists(destinationDirectory)) { Error("Error: Destination directory does not exist."); } if (resolution != "minute" && resolution != "second" && resolution != "tick") { Error("Error: Resolution specified is not supported. Please enter tick, second or minute"); } } } }