using System;
using System.Collections.Generic;
using System.Text;
using MarketData.Generator.MovingAverage;
using MarketData.MarketDataModel;
// Filename: BollingerBandGenerator.cs
// Author:Sean Kessler
// Date:05/2013

namespace MarketData.Generator
{
  /// <summary>GenerateBollingerBands - Bollinger band generator utility class</summary>
  public class BollingerBandGenerator
  {
    private BollingerBandGenerator()
    {
    }
    public static BollingerBands GenerateBollingerBands(Prices prices,int movingAverageDays=20)
    {
      try
      {
        double standardDeviations = 2.00;
        BollingerBands bollingerBands = new BollingerBands();
        Dictionary<DateTime, DMADeviation> deviationsByDate = new Dictionary<DateTime, DMADeviation>();
        Dictionary<DateTime, DMAPrice> averagesByDate = new Dictionary<DateTime, DMAPrice>();

        if (movingAverageDays < 20) standardDeviations = 1.9;
        else if (movingAverageDays >= 20) standardDeviations = 2.1;
        if (null == prices || prices.Count < movingAverageDays * 2) return null;
        DMAPrices dmaPrices = MovingAverageGenerator.GenerateMovingAverage(prices, movingAverageDays);
        DMADeviations dmaDeviations = MovingDeviation.GenerateMovingDeviation(prices, movingAverageDays);
        for (int index = 0; index < dmaPrices.Count; index++)
        {
          DMAPrice dmaPrice = dmaPrices[index];
          if (!averagesByDate.ContainsKey(dmaPrice.Date)) averagesByDate.Add(dmaPrice.Date, dmaPrice);
        }
        for (int index = 0; index < dmaDeviations.Count; index++)
        {
          DMADeviation dmaDeviation = dmaDeviations[index];
          if (!deviationsByDate.ContainsKey(dmaDeviation.Date)) deviationsByDate.Add(dmaDeviation.Date, dmaDeviation);
        }
        for (int index = 0; index < prices.Count; index++)
        {
          Price price = prices[index];
          if (!deviationsByDate.ContainsKey(price.Date) || !averagesByDate.ContainsKey(price.Date)) continue;
          DMADeviation dmaDeviation = deviationsByDate[price.Date];
          DMAPrice dmaPrice = averagesByDate[price.Date];
          BollingerBandElement bollingerBandElement = new BollingerBandElement();
          bollingerBandElement.Symbol = price.Symbol;
          bollingerBandElement.Date = price.Date;
          bollingerBandElement.Open = price.Open;
          bollingerBandElement.High = price.High;
          bollingerBandElement.Low = price.Low;
          bollingerBandElement.Close = price.Close;
          bollingerBandElement.Volume = price.Volume;
          bollingerBandElement.SMAN = dmaPrice.AVGPrice;
          bollingerBandElement.StDevN = dmaDeviation.StDevPrice;
          bollingerBandElement.K = bollingerBandElement.SMAN + (standardDeviations * bollingerBandElement.StDevN);
          bollingerBandElement.L = bollingerBandElement.SMAN - (standardDeviations * bollingerBandElement.StDevN);
          bollingerBandElement.KL1 = bollingerBandElement.SMAN + ((standardDeviations - 1) * bollingerBandElement.StDevN);
          bollingerBandElement.LP1 = bollingerBandElement.SMAN - ((standardDeviations - 1) * bollingerBandElement.StDevN);
          bollingerBands.Add(bollingerBandElement);
        }
        return bollingerBands;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception);
        return null;
      }
    }
  }
}
