using System;
using System.Collections.Generic;
using MarketData.Generator.MovingAverage;
using MarketData.MarketDataModel;

// Filename: StochasticsGenerator.cs
// Author:Sean Kessler
// Date:08/2013

namespace MarketData.Generator
{
  /// <summary>StochasticsGenerator - StochasticsGenerator utility class</summary>
  public class StochasticsGenerator
  {
    public static Stochastics GenerateStochastics(Prices prices, int periodN=9,int periodX=3)
    {
      try
      {
        Stochastics stochastics = new Stochastics();
        DMAPricesByDate dmaLNPricesByDate = null;  // these are the min(low) for the period-n
        DMAPricesByDate dmaHNPricesByDate = null; // these are the max(high) for the period-n
        DMAPrices dmaLN = MovingAverageGenerator.GenerateMovingMinsOnLow(prices, periodN);
        DMAPrices dmaHN = MovingAverageGenerator.GenerateMovingMaxOnHigh(prices, periodN);
        dmaLNPricesByDate = dmaLN.GetDMAPricesByDate();
        dmaHNPricesByDate = dmaHN.GetDMAPricesByDate();
        int stopCount;

        stopCount = Math.Max(periodN, periodX)+1;  // clamp the solution set the range
        for (int index = 0; index < prices.Count - stopCount; index++)
        {
          Price price = prices[index];
          StochasticElement stochasticElement = new StochasticElement();
          if(!dmaLNPricesByDate.ContainsKey(price.Date))continue;
          if(!dmaHNPricesByDate.ContainsKey(price.Date))continue;
          stochasticElement.Date = price.Date;
          stochasticElement.Symbol = price.Symbol;
          stochasticElement.Open = price.Open;
          stochasticElement.High = price.High;
          stochasticElement.Low = price.Low;
          stochasticElement.Close = price.Close;
          stochasticElement.LN = dmaLNPricesByDate[price.Date].MinPrice;  // min low for period N
          stochasticElement.HN = dmaHNPricesByDate[price.Date].MaxPrice;  // max high for period N
          stochasticElement.HX = CalculateHX(index, prices, dmaLN, periodX);   // sum (CCL-LN) for past periodX
          stochasticElement.LX = CalculateLX(index, dmaHN, dmaLN, periodX);   // sum(HN-LN) for past periodX
          stochasticElement.PK = 100 * (price.Close - stochasticElement.LN) / (stochasticElement.HN - stochasticElement.LN); //  100*(CCL-LN)/(HN-LN)
          stochasticElement.PD = 100 * (stochasticElement.HX / stochasticElement.LX);   // 100*(HX/LX)
          stochastics.Add(stochasticElement);
        }
        return stochastics;
      }
      catch (Exception exception)
      {
        MDTrace.WriteLine(LogLevel.DEBUG,exception);
        return null;
      }
    }
// calculate the x-period sum of (CCL-LN)
    private static double CalculateHX(int startingIndex,Prices prices,DMAPrices lnPrices,int periodK)
    {
      try
      {
        double sum = 0.00;
        for (int index = startingIndex; index < startingIndex + periodK; index++)
        {
          Price price = prices[index];
          DMAPrice lnPrice = lnPrices[index];
          sum+=(price.Close-lnPrice.MinPrice);
        }
        return sum;
      }
      catch(Exception /*exception*/)
      {
        return double.NaN;
      }
    }
//sum(HN-LN) for past period K
    private static double CalculateLX(int startingIndex,DMAPrices hnPrices,DMAPrices lnPrices, int periodK)
    {
      try
      {
        double sum = 0.00;
        for (int index = startingIndex; index < startingIndex + periodK; index++)
        {
          DMAPrice hnPrice = hnPrices[index];
          DMAPrice lnPrice = lnPrices[index];
          sum+=(hnPrice.MaxPrice-lnPrice.MinPrice);
        }
        return sum;
      }
      catch (Exception /*exception*/)
      {
        return double.NaN;
      }
    }
  }
}
