/// <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> /// Frees the orders for a ticker when it finished. /// </summary> /// <param name="tickerAndExchange">Ticker to free</param> public void PurgeTickerOrders(TickerExchangePair tickerAndExchange) { TickerStrategyOrders[tickerAndExchange.GetHashCode()] = null; }
/// <summary> /// Gets the symbol data from either memory, disk, or a server. /// </summary> /// <param name="ticker">Ticker to get data for</param> /// <param name="start">Start date for the data</param> /// <param name="end">End date for the data</param> /// <returns>Data (price, volume, etc) for the ticker</returns> public TickerData GetTickerData(TickerExchangePair ticker, DateTime start, DateTime end) { TickerData data = new TickerData(ticker); // The symbol exists in memory already. int key = ticker.GetHashCode(); if (_symbolsInMemory.ContainsKey(key)) { TickerData inMemoryData = _symbolsInMemory[key]; // We don't have all the data in memory past the end, so we need to get that data and append it. if (end > inMemoryData.End || start < inMemoryData.Start) { data = GetDataFromDiskOrServer(ticker, start, end); // Update the data in memory so it has it next time it runs. _symbolsInMemory[key] = data; // Return only the dates requested. data = data.SubSet(start, end); } // Not requesting everything that is in the memory. This is generally the case. else if (start > inMemoryData.Start || end < inMemoryData.End) { data = inMemoryData.SubSet(start, end); } // We wanted everything that is memory. else { data = inMemoryData; } } // Symbol isn't in memory so we need to load from the disk or the server. else { // Always start by loading everything we have our earliest date so that // anytime we eventually will have all the data saved allowing us to // test lots of different date ranges without having to hit the disk or internet. data = GetDataFromDiskOrServer(ticker, start, end); if (data != null) { // Save in memory for next time. _symbolsInMemory[key] = data; data = data.SubSet(start, end); } } if (data != null) { // Save all the dates that this ticker has so that we have a list of dates that we can // iterate through for trading periods. This is because each ticker can potentially have // different trading dates but for the main sim we want to go through all dates and if // the ticker has data for that time, we'll use it. lock (_dateLock) { for (int i = 0; i < data.Dates.Count; i++) { if (SimTickerDates.ContainsKey(data.Dates[i]) == false) { SimTickerDates[data.Dates[i]] = true; } } } } return(data); }