256 lines
10 KiB
C#
256 lines
10 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using MarketData.MarketDataModel;
|
|
using MarketData.DataAccess;
|
|
using MarketData.Numerical;
|
|
using MarketData.Utils;
|
|
|
|
namespace MarketData.Generator
|
|
{
|
|
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<DateTime, DMAPrice> ma200ByDate = new Dictionary<DateTime, DMAPrice>();
|
|
Dictionary<DateTime, DMAPrice> ma100ByDate = new Dictionary<DateTime, DMAPrice>();
|
|
Dictionary<DateTime, DMAPrice> ma55ByDate = new Dictionary<DateTime, DMAPrice>();
|
|
Dictionary<DateTime, DMAPrice> ma21ByDate = new Dictionary<DateTime, DMAPrice>();
|
|
Dictionary<DateTime, DMAPrice> ma5ByDate = new Dictionary<DateTime, DMAPrice>();
|
|
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;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 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.
|
|
/// </summary>
|
|
/// <param name="prices"></param>
|
|
/// <param name="dayCount"></param>
|
|
/// <returns></returns>
|
|
public static DMAPrices GenerateExponentialMovingAverage(Prices prices,int dayCount)
|
|
{
|
|
try
|
|
{
|
|
if(null==prices||prices.Count<dayCount+1)return null; // (i.e.) a 20 day ExponentialMovingAverage requires 21 days of data
|
|
double beta=2.00/((double)dayCount+1.00);
|
|
DMAPrices emaPrices=new DMAPrices();
|
|
|
|
DMAPrices smaPrices=GenerateMovingAverage(prices,dayCount);
|
|
if(null==smaPrices||smaPrices.Count<dayCount)return null;
|
|
for(int index=0;index<smaPrices.Count;index++)
|
|
{
|
|
DMAPrice smaPrice=smaPrices[index];
|
|
DMAPrice emaPrice=new DMAPrice();
|
|
if(0==index)
|
|
{
|
|
emaPrice.Symbol=smaPrice.Symbol;
|
|
emaPrice.Date=smaPrice.Date;
|
|
emaPrice.AVGPrice=smaPrice.AVGPrice;
|
|
emaPrice.CurrentPrice=smaPrice.CurrentPrice;
|
|
emaPrice.MaxPrice=smaPrice.MaxPrice;
|
|
emaPrice.MinPrice=smaPrice.MinPrice;
|
|
emaPrices.Add(emaPrice);
|
|
}
|
|
else
|
|
{
|
|
DMAPrice prevEMA=emaPrices[emaPrices.Count-1];
|
|
emaPrice.Symbol=smaPrice.Symbol;
|
|
emaPrice.Date=smaPrice.Date;
|
|
emaPrice.CurrentPrice=smaPrice.CurrentPrice;
|
|
emaPrice.MaxPrice=smaPrice.MaxPrice;
|
|
emaPrice.MinPrice=smaPrice.MinPrice;
|
|
emaPrice.AVGPrice = prevEMA.AVGPrice+beta*(smaPrice.CurrentPrice - prevEMA.AVGPrice);
|
|
emaPrices.Add(emaPrice);
|
|
}
|
|
}
|
|
return emaPrices;
|
|
}
|
|
catch (Exception exception)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,exception);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary>Generates a dayCount moving average given prices.</summary>
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|