using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MarketData.Numerical;
using MarketData.MarketDataModel;
using MarketData.DataAccess;
using MarketData.Cache;
using MarketData.Utils;

namespace MarketData.Generator.Indicators
{
// ***********************************************************************************
  public class OverExtendedIndicator
  {
    private static double marginPercent=1.50;    // The default margin is 1.00.  1.50 Gives the best results in backtests from 2013->2021
    private OverExtendedIndicator()              // Also, regarding VioaltionThresshold below.... the best results were obtained with MarginePercent=1.5 and ViolationThresshol=1.00
    {
    }
// UseOverExtendedIndicator:true/false
// UseOverExtendedIndicatorDays:45
// UseOverExtendedViolationThreshhold:2 breaks >=2 this number are considered to be violations
// This Indicator determines if a price is overextended by looking at the K band of the bollinger band over the past "dayCount" days.
// If closing price breaks the K band by more than 1.00% then we consider that to be an indication that the price is overextended.
    public static bool? IsOverextended(String symbol,DateTime pricingDate,int dayCount=20) 
    {
      bool isOverExtended=false;
      Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,dayCount*4);
      if(null==prices || 0==prices.Count)return null;
      BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices,dayCount);
      if(null==bollingerBands)return false;
      bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList());
      BollingerBandElement item=bollingerBands.Where(x => x.Close>x.K && (((x.Close-x.K)/x.K)*100.00)>marginPercent).FirstOrDefault();
      if(null!=item)isOverExtended=true;
      return isOverExtended;
    }
// This method considers an overextended condition based upon an allowable number of upper band breaks 
    public static bool? IsOverextended(String symbol,DateTime pricingDate,int dayCount=20,int violationThreshhold=1)
    {
      bool isOverExtended=false;
      Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,dayCount*4);
      if(null==prices||0==prices.Count) return null;
      BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices,dayCount);
      if(null==bollingerBands) return false;
      bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList());
      List<BollingerBandElement> items=bollingerBands.Where(x => x.Close>x.K&&(((x.Close-x.K)/x.K)*100.00)>marginPercent).ToList();
      if(null==items)return null;
      if(items.Count>violationThreshhold)isOverExtended=true;
      return isOverExtended;
    }
    // This method considers an overextended condition based upon an allowable number of upper band breaks and user supplied marginPercent 
    public static bool? IsOverextended(String symbol,DateTime pricingDate,int dayCount=20,int violationThreshhold=1,double paramMarginPercent=1.00)
    {
      bool isOverExtended=false;
      Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,dayCount*4);
      if(null==prices||0==prices.Count) return null;
      BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices,dayCount);
      if(null==bollingerBands) return false;
      bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList());
      List<BollingerBandElement> items=bollingerBands.Where(x => x.Close>x.K&&(((x.Close-x.K)/x.K)*100.00)>paramMarginPercent).ToList();
      if(null==items) return null;
      if(items.Count>violationThreshhold) isOverExtended=true;
      return isOverExtended;
    }
    public static int? OverExtendedCount(String symbol,DateTime pricingDate,int dayCount=20)
    {
      Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,pricingDate,dayCount*4);
      if(null==prices||0==prices.Count) return null;
      BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices,dayCount);
      if(null==bollingerBands) return null;
      bollingerBands=new BollingerBands(bollingerBands.Take(dayCount).ToList());
      List<BollingerBandElement> items=bollingerBands.Where(x => x.Close>x.K).ToList();
      if(null==items)return null;
      return items.Count; 
    }
  }
}
