using System; using System.Collections.Generic; using MarketData.MarketDataModel; using MarketData.DataAccess; using MarketData.Numerical; using MarketData.Utils; namespace MarketData.Generator.MovingAverage { public class MovingAverageGenerator { public static readonly int DayCount200=200; public static readonly int DayCount100=100; public static readonly int DayCount55=55; public static readonly int DayCount50=50; public static readonly int DayCount21=21; public static readonly int DayCount5=5; private MovingAverageGenerator() { } public static MovingAverages GenerateMovingAverages(String symbol,int dayCount=180) { try { Dictionary ma200ByDate = new Dictionary(); Dictionary ma100ByDate = new Dictionary(); Dictionary ma55ByDate = new Dictionary(); Dictionary ma21ByDate = new Dictionary(); Dictionary ma5ByDate = new Dictionary(); if (null == symbol) return null; String companyName = PricingDA.GetNameForSymbol(symbol); DateGenerator dateGenerator = new DateGenerator(); DateTime startDate = dateGenerator.GetPrevBusinessDay(DateTime.Now); Prices prices = PricingDA.GetPrices(symbol, startDate, dayCount); if (null == prices || 0 == prices.Count) { MDTrace.WriteLine(LogLevel.DEBUG,"No prices for symbol '" + symbol + "'"); return null; } Price latestPrice = prices[0]; DMAPrices ma200= GenerateMovingAverage(prices, DayCount200); DMAPrices ma100 = GenerateMovingAverage(prices, DayCount100); DMAPrices ma55 = GenerateMovingAverage(prices, DayCount55); DMAPrices ma21 = GenerateMovingAverage(prices, DayCount21); DMAPrices ma5 = GenerateMovingAverage(prices, DayCount5); for (int index = 0; index < ma200.Count; index++) ma200ByDate.Add(ma200[index].Date,ma200[index]); for (int index = 0; index < ma100.Count; index++) ma100ByDate.Add(ma100[index].Date, ma100[index]); for (int index = 0; index < ma55.Count; index++) ma55ByDate.Add(ma55[index].Date, ma55[index]); for (int index = 0; index < ma21.Count; index++) ma21ByDate.Add(ma21[index].Date, ma21[index]); for (int index = 0; index < ma5.Count; index++) ma5ByDate.Add(ma5[index].Date, ma5[index]); MovingAverages movingAverages = new MovingAverages(); movingAverages.ThruDate = prices[0].Date; movingAverages.FromDate = prices[prices.Count - 1].Date; for (int index = 0; index < prices.Count; index++) { Price price = prices[index]; DMAPrice ma200Price = null; DMAPrice ma100Price = null; DMAPrice ma55Price = null; DMAPrice ma21Price = null; DMAPrice ma5Price = null; if (ma55ByDate.ContainsKey(price.Date)) ma55Price=ma55ByDate[price.Date]; if (ma21ByDate.ContainsKey(price.Date)) ma21Price = ma21ByDate[price.Date]; if (ma5ByDate.ContainsKey(price.Date)) ma5Price = ma5ByDate[price.Date]; if(ma200ByDate.ContainsKey(price.Date))ma200Price = ma200ByDate[price.Date]; if(ma100ByDate.ContainsKey(price.Date)) ma100Price = ma100ByDate[price.Date]; MovingAverageElement movingAverageElement = new MovingAverageElement(); movingAverageElement.Symbol = price.Symbol; movingAverageElement.Date = price.Date; movingAverageElement.Close = price.Close; movingAverageElement.High = price.High; movingAverageElement.Low = price.Low; movingAverageElement.MA200 = null==ma200Price?double.NaN:ma200Price.AVGPrice; movingAverageElement.MA100 = null == ma100Price ? double.NaN : ma100Price.AVGPrice; movingAverageElement.MA55 = null==ma55Price?double.NaN:ma55Price.AVGPrice; movingAverageElement.MA21 = null==ma21Price?double.NaN:ma21Price.AVGPrice; movingAverageElement.MA5 = null==ma5Price?double.NaN:ma5Price.AVGPrice; movingAverages.Add(movingAverageElement); } return movingAverages; } catch (Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception); return null; } } public static DMAValues GenerateMovingAverage(DMAValues values,int dayCount) { try { DMAValues dmaValues = new DMAValues(); for (int index = 0; index < values.Count; index++) { DMAValue value = values[index]; DMAValue dmaValue = new DMAValue(); dmaValue.Date = value.Date; float[] pricesArray = values.GetValues(index, dayCount); if (null == pricesArray) break; dmaValue.MAValue = Numerics.Mean(ref pricesArray); dmaValue.Value = value.Value; if (double.IsNaN(dmaValue.MAValue)) continue; dmaValues.Add(dmaValue); } return dmaValues; } catch (Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception); return null; } } /// /// The EMA coverage shoudld be the same as the simple moving average. If you have 10 elements in the SMA then you should have 10 elements in the EMA /// The EMA smooths the line by applying a smoothing (Beta) where Beta=1/(dayCount+1). Foe example if you are wanting to calculate the /// 20 day exponential moving average over a series then Beta=2/(20+1)=.095 /// The formula: EMA=prevEMA.AVGPrice+beta*(smaPrice.CurrentPrice - prevEMA.AVGPrice) /// Tom Basso uses a 9 day(Fast) and 41 day(Slow) exponential moving average crossover to determine change in trend direction. /// /// /// /// public static DMAPrices GenerateExponentialMovingAverage(Prices prices,int dayCount) { try { if(null==prices||prices.CountGenerates a dayCount moving average given prices. public static DMAPrices GenerateMovingAverage(Prices prices, int dayCount) { try { DMAPrices dmaPrices = new DMAPrices(); for (int index = 0; index < prices.Count; index++) { Price price = prices[index]; DMAPrice dmaPrice = new DMAPrice(); dmaPrice.Symbol = price.Symbol; dmaPrice.Date = price.Date; float[] pricesArray = prices.GetPrices(index, dayCount); if (null == pricesArray) break; dmaPrice.AVGPrice = Numerics.Mean(ref pricesArray); if (double.IsNaN(dmaPrice.AVGPrice)) continue; dmaPrice.CurrentPrice = price.Close; dmaPrices.Add(dmaPrice); } return dmaPrices; } catch (Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception); return null; } } public static DMAPrices GenerateMovingMinsOnLow(Prices prices, int dayCount) { try { DMAPrices dmaPrices = new DMAPrices(); for (int index = 0; index < prices.Count; index++) { Price price = prices[index]; DMAPrice dmaPrice = new DMAPrice(); dmaPrice.Symbol = price.Symbol; dmaPrice.Date = price.Date; float[] pricesArray = prices.GetPricesLow(index, dayCount); if (null == pricesArray) break; dmaPrice.MinPrice = Numerics.Min(ref pricesArray); if (double.IsNaN(dmaPrice.MinPrice)) continue; dmaPrice.CurrentPrice = price.Low; dmaPrices.Add(dmaPrice); } return dmaPrices; } catch (Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString()); return null; } } public static DMAPrices GenerateMovingMaxOnHigh(Prices prices, int dayCount) { try { DMAPrices dmaPrices = new DMAPrices(); for (int index = 0; index < prices.Count; index++) { Price price = prices[index]; DMAPrice dmaPrice = new DMAPrice(); dmaPrice.Symbol = price.Symbol; dmaPrice.Date = price.Date; float[] pricesArray = prices.GetPricesHigh(index, dayCount); if (null == pricesArray) break; dmaPrice.MaxPrice = Numerics.Max(ref pricesArray); if (double.IsNaN(dmaPrice.MaxPrice)) continue; dmaPrice.CurrentPrice = price.High; dmaPrices.Add(dmaPrice); } return dmaPrices; } catch (Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString()); return null; } } } }