/// <summary> /// Outputs all the overall files for the main strategy. /// </summary> void OutputMainStrategy() { if (Simulator.Orders.StrategyDictionary.ContainsKey("MainStrategy".GetHashCode())) { string jsonOutput; string filename; List<Order> mainStrategyOrders = Simulator.Orders.StrategyDictionary["MainStrategy".GetHashCode()].ToList(); StrategyStatistics mainStratStats = new StrategyStatistics("MainStrategy", Order.OrderType.Long); // Sort so we can find out the most losers in a row. mainStrategyOrders.Sort((a, b) => b.BuyDate.CompareTo(a.BuyDate)); for (int i = 0; i < mainStrategyOrders.Count; i++) { mainStratStats.AddOrder(mainStrategyOrders[i]); } mainStratStats.CalculateStatistics(); jsonOutput = JsonConvert.SerializeObject(mainStratStats); filename = _outputFolder + "overall.json"; File.WriteAllText(filename, jsonOutput); List<Order> mainOrders = mainStrategyOrders; mainOrders.RemoveAll(order => order.Status == Order.OrderStatus.Cancelled); jsonOutput = JsonConvert.SerializeObject(mainOrders); filename = _outputFolder + "overall-orders.json"; File.WriteAllText(filename, jsonOutput); jsonOutput = JsonConvert.SerializeObject(Simulator.Broker); filename = _outputFolder + "overall-account.json"; File.WriteAllText(filename, jsonOutput); } }
/// <summary> /// Outputs info about how each ticker has performed. /// </summary> private void OutputTickerStats() { List<StrategyStatistics> allTickerStatistics = new List<StrategyStatistics>(); foreach (KeyValuePair<int, List<Order>> tickerOrder in Simulator.Orders.TickerDictionary) { List<Order> orders = tickerOrder.Value; if (orders.Count > 0) { string tickerName = orders[0].Ticker.TickerAndExchange.ToString(); StrategyStatistics tickerStats = new StrategyStatistics(tickerName, Order.OrderType.Long); // Catagorize and total all the orders by ticker. for (int i = 0; i < orders.Count; i++) { // Get the strategy name but skip the main strategy as it gets process differently. string strategyName = orders[i].StrategyName; if (strategyName == "MainStrategy") { continue; } tickerStats.AddOrder(orders[i]); } tickerStats.CalculateStatistics(); allTickerStatistics.Add(tickerStats); //jsonOutput = JsonConvert.SerializeObject(tickerStats, Formatting.Indented); //folderName = _outputFolder + "ticker-statistics\\" + tickerName; //filename = folderName + "\\overall.json"; //Directory.CreateDirectory(folderName); //File.WriteAllText(filename, jsonOutput); } } allTickerStatistics.Sort((a, b) => b.Gain.CompareTo(a.Gain)); string jsonOutput = JsonConvert.SerializeObject(allTickerStatistics); string filename = _outputFolder + "overall-tickers.json"; File.WriteAllText(filename, jsonOutput); // Output a csv of all the stocks with positive gains in case we want to // use that file as an input to do even better. allTickerStatistics.RemoveAll(a => a.Gain <= 0); StringBuilder sb = new StringBuilder(); for (int i = 0; i < allTickerStatistics.Count; i++) { string[] split = allTickerStatistics[i].StrategyName.Split('-'); sb.Append(split[0] + "," + split[1]); if (i + 1 < allTickerStatistics.Count) { sb.Append("," + Environment.NewLine); } } filename = _outputFolder + "positive-gainers.csv"; File.WriteAllText(filename, sb.ToString()); }
/// <summary> /// Calculates things like win/loss percent, gain, etc. for the strategy used on the ticker. /// </summary> /// <param name="strategyName">Name of the strategy the statistics are for</param> /// <param name="orderType">Type of orders placed with this strategy (long or short)</param> /// <param name="tickerAndExchange">Ticker the strategy used</param> /// <param name="currentBar">Current bar of the simulation</param> /// <param name="maxBarsAgo">Maximum number of bars in the past to consider for calculating</param> /// <returns>Class holding the statistics calculated</returns> public StrategyStatistics GetStrategyStatistics(string strategyName, double orderType, TickerExchangePair tickerAndExchange, int currentBar, int maxBarsAgo) { // Orders that started less than this bar will not be considered. int cutoffBar = currentBar - maxBarsAgo; if (cutoffBar < 0) { cutoffBar = 0; } // Get the list of orders to search. StrategyStatistics stats = new StrategyStatistics(strategyName, orderType); List <Order> orderList = null; if (strategyName.Length > 0 && tickerAndExchange == null) { int strategyKey = strategyName.GetHashCode(); if (StrategyDictionary.ContainsKey(strategyKey)) { orderList = StrategyDictionary[strategyKey].ToList(); } } else if (tickerAndExchange != null) { int tickerHash = tickerAndExchange.GetHashCode(); if (TickerDictionary.ContainsKey(tickerHash)) { orderList = TickerDictionary[tickerHash]; } } if (orderList != null) { for (int i = orderList.Count - 1; i >= 0; i--) { Order order = orderList[i]; if (order.IsFinished() && order.StrategyName == strategyName && order.BuyBar >= cutoffBar && order.Type == orderType && stats.NumberOfOrders < Simulator.Config.MaxLookBackOrders) { stats.AddOrder(order); } } } if (stats.NumberOfOrders > Simulator.Config.MinRequiredOrders) { stats.CalculateStatistics(); } else { stats = new StrategyStatistics(strategyName, orderType); } return(stats); }
/// <summary> /// Calculates things like win/loss percent, gain, etc. for the ticker. /// </summary> /// <param name="tickerAndExchange">Ticker to calculate for</param> /// <param name="currentBar">Current bar of the simulation</param> /// <param name="maxBarsAgo">Maximum number of bars in the past to consider for calculating</param> /// <returns>Class holding the statistics calculated</returns> public StrategyStatistics GetTickerStatistics(TickerExchangePair tickerAndExchange, int currentBar, int maxBarsAgo) { // Orders that started less than this bar will not be considered. int cutoffBar = currentBar - maxBarsAgo; if (cutoffBar < 0) { cutoffBar = 0; } // Order type doesn't matter here since we are just using this class to // output overall ticker info which could be from any order type. It will // get ignored on the web output display. StrategyStatistics stats = new StrategyStatistics(tickerAndExchange.ToString(), Order.OrderType.Long); int tickerHash = tickerAndExchange.GetHashCode(); if (TickerDictionary.ContainsKey(tickerHash)) { List <Order> tickerOrders = TickerDictionary[tickerHash]; for (int i = tickerOrders.Count - 1; i >= 0; i--) { Order order = tickerOrders[i]; if (order.BuyBar >= cutoffBar) { stats.AddOrder(order); } } } // Only count the statistics if we have a bit more data to deal with. // We want to avoid having a strategy say it's 100% correct when it // only has 1 winning trade. if (stats.NumberOfOrders > Simulator.Config.MinRequiredOrders) { stats.CalculateStatistics(); } else { // For the same reasons as earlier in this function, order type doesn't matter here. stats = new StrategyStatistics(tickerAndExchange.ToString(), Order.OrderType.Long); } return(stats); }
/// <summary> /// Returns the size the order should be based on performance. /// </summary> /// <param name="originalSize">Original size of the order returned from the strategy</param> /// <param name="ticker">Ticker we are buying</param> /// <returns>See summary</returns> private double GetOrderSize(int currentBar, double originalSize, double orderType, TickerData ticker) { StrategyStatistics stats = Orders.GetStrategyStatistics("MainStrategy", orderType, null, currentBar, Simulator.Config.MaxLookBackBars); // Use the Kelly Criterion to compute how much to invest // %K = W - [(1 - W) / R] // W is the winning probability of the past trades. // R is the win/loss ratio from the past trades. double winPercent = (orderType == Order.OrderType.Long ? stats.LongWinPercent : stats.ShortWinPercent) / 100.0; double avgGain = orderType == Order.OrderType.Long ? stats.LongWinAvg : stats.ShortWinAvg; double avgLoss = orderType == Order.OrderType.Long ? stats.LongLossAvg : stats.ShortLossAvg; double percentK = avgGain == 0.0 || avgLoss == 0.0 ? 1.0 : winPercent - ((1 - winPercent) / (Math.Abs(avgGain) / Math.Abs(avgLoss))); // Minimum investment percent since we got this order for a reason, so we want // to invest something. if (percentK < 0.25) { percentK = 0.25; } return originalSize;// *percentK; }
/// <summary> /// Outputs the all the statistics for all strategies and the overall stats for each. /// </summary> void OutputStrategyStats() { if (Simulator.Config.UseAbbreviatedOutput == true) { return; } ConcurrentBag<StrategyStatistics> allStrategyStatistics = new ConcurrentBag<StrategyStatistics>(); #if DEBUG foreach (KeyValuePair<int, ConcurrentBag<Order>> strategy in Simulator.Orders.StrategyDictionary) #else Parallel.ForEach(Simulator.Orders.StrategyDictionary, strategy => #endif { string jsonOutput; string folderName; string filename; ConcurrentBag<Order> orders = strategy.Value; if (orders.Count > Simulator.Config.MinRequiredOrders) { // Get the strategy name but skip the main strategy as it gets process differently. string strategyName = orders.First().StrategyName; if (strategyName == "MainStrategy") { #if DEBUG continue; #else return; #endif } Dictionary<int, StrategyTickerPairStatistics> tickersForThisStrategy = new Dictionary<int, StrategyTickerPairStatistics>(); StrategyStatistics stratStats = new StrategyStatistics(strategyName, orders.First().Type); // Catagorize and total all the orders for this strategy by the ticker they are associated with. foreach (Order order in orders) { int tickerHash = order.Ticker.TickerAndExchange.GetHashCode(); string tickerName = order.Ticker.TickerAndExchange.ToString(); // If we haven't created the output for this ticker then create it. if (!tickersForThisStrategy.ContainsKey(tickerHash)) { tickersForThisStrategy[tickerHash] = new StrategyTickerPairStatistics(strategyName, tickerName, order.DependentIndicatorNames); } tickersForThisStrategy[tickerHash].AddOrder(order); stratStats.AddOrder(order); } stratStats.CalculateStatistics(); allStrategyStatistics.Add(stratStats); // Output the info about each ticker for this strategy. List<StrategyStatistics> overallList = new List<StrategyStatistics>(); foreach (KeyValuePair<int, StrategyTickerPairStatistics> item in tickersForThisStrategy) { // This hasn't been calculated yet. item.Value.CalculateStatistics(); // Save the info for this strategy by the ticker. jsonOutput = JsonConvert.SerializeObject(item.Value); folderName = _outputFolder + "strategies\\" + strategyName; filename = folderName + "\\" + item.Value.TickerName + ".json"; Directory.CreateDirectory(folderName); File.WriteAllText(filename, jsonOutput); // Save for the overall stats to be outputted later. // Order type doesn't matter for tickers and will get ignored in the web display. StrategyStatistics tickerStats = new StrategyStatistics(item.Value.TickerName, Order.OrderType.Long); tickerStats.InitFromStrategyTickerPairStatistics(item.Value); overallList.Add(tickerStats); } // Output the overall stats for this strategy. jsonOutput = JsonConvert.SerializeObject(overallList); folderName = _outputFolder + "strategies\\" + strategyName; filename = folderName + "\\overall.json"; Directory.CreateDirectory(folderName); File.WriteAllText(filename, jsonOutput); } #if DEBUG } #else }); #endif string overallJsonOutput = JsonConvert.SerializeObject(allStrategyStatistics.ToArray()); string overallFilename = _outputFolder + "overall-strategies.json"; File.WriteAllText(overallFilename, overallJsonOutput); }