using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MarketData.Generator.CMMomentum
{
  public class CMParams
  {
    public CMParams()
    {
      DayCount = 90;                                              // The lookback period
      AnalysisDate = DateTime.Now.Date;                           // The analysis date of the run
      TradeDate = DateTime.Now;                                   // The current trade date
      DailyReturnLimit = .25;                                     // .15 was producing a lot unqualified candidates, this test to .25.  Reject candidates that exceed DailyReturnLimit within the lookback period
      MovingAverageConstraintDays = 100;                          // If current price of a candidate is below the DMA(MovingAverageConstraintDays) then it is rejected
      FallbackCandidateBestOf = "SHV,NEAR,BIL,GSY,AGG,ACWX,GSY,SCHF,IXUS,DBEF,IEFA";  // if set then the fallback candidate is selected as the best 252 day return in this comma seperated list (i.e.) "SHV,ACWX,AGG" 
      FallbackMaxAlloc = 1000;                                    // Max Allocation for Fallback candidate.  
      Benchmark = "SPY";                                          // This is the benchmark security
      BenchmarkMovingAverageDays = 200;                           // If the latest benchmark Close is below DMA(BenchmarkMovingAverageDays) then we switch the strategy to the fallback candidates
      HoldingPeriod = 3;                                          // 3 is the default.  This is in months.
      MaxPositions = 3;                                           // 3 is the default
      NoTradeSymbols = "GBTC,YOKU,PNY,RFMD,ASAZY";                // ASAZY came up as candidate during 3/30 run but not available on Robinhood
      InitialCash = 10000;                                        // The initial cash 
      TargetBeta = 1.00;                                          // The target Beta used to perform allocation for risk
      BetaMonths = 6;                                             // The number of months to use for Beta
      MarketCapLowerLimit = 1000000000;                           // MarketCap lower limit 1,000,000,000
      UseMaxBeta = false;                                         // Utilize the MaxBeta filter
      MaxBeta = 10.00;                                            // Candidates with Beta that exceed this are rejected.
      UseMaxPositionBucketWeight=false;                           // When set to true then ensure that no single position within a bucket can exceed UseMaxPositionBucketWeightMaxWeight percent
      UseMaxPositionBucketWeightMaxWeight=.60;                    // The maximum weight any single position can be allocated within a bucket.  .60 is 60%
      UseOverExtendedIndicator=false;                             // The OverExtendedIndicator uses the upper K band of the Bollinger Band and compares that to the Price.Close on that day.  It does this comparison across dayCount days start at TradeDate and going back through time
      UseOverExtendedIndicatorDays=10;                            // This is the number of days of history to scan for OverExtension detetction.  10 gives best results in backtest
      UseOverExtendedIndicatorViolationThreshhold=1;              // This is the number of items that constitute an upper band break. (i.e.) if this is set to 1 then a single band break is a violation... if 2 then >=2 band breaks are a violation etc.,   1.00 gives the best results in backtest
      UseOverExtendedIndicatorMarginPercent=1.00;                 // Add this in so we can control the margin.  The best value is 1.00 from backtest results
			UseCNN=false;		                                            // If set to true then use convolutional network to assist in ranking the candidates
			UseCNNHost="http://127.0.0.1:5000";												  // The url for the UseCNNHost
			UseCNNDayCount=270;																					// The daycount to use for the image data to present to the convolutional network
      UseCNNRewardPercentDecimal=.20;                             // If a prediction is positive then Score is increased by the specified percentage. Tests using 20% reward show 25% improvement in gains versus not running the CNN
    }
    public int DayCount { get; set; }
    public DateTime AnalysisDate { get; set; }
    public DateTime TradeDate { get; set; }
    public double DailyReturnLimit { get; set; }
    public int MovingAverageConstraintDays { get; set; }
    public String FallbackCandidateBestOf { get; set; }
    public double FallbackMaxAlloc { get; set; }
    public String Benchmark { get; set; }
    public int BenchmarkMovingAverageDays { get; set; }
    public int HoldingPeriod { get; set; }
    public int MaxPositions { get; set; }
    public String NoTradeSymbols{ get; set; }
    public List<String> NoTradeSymbolsList { get { return null==NoTradeSymbols?null:Utility.ToList(NoTradeSymbols); } }
    public double InitialCash { get; set; }
    public double TargetBeta { get; set; }
    public int BetaMonths { get; set; }
    public double MaxBeta { get; set; }
    public bool UseMaxBeta { get; set; }
    public double MarketCapLowerLimit { get; set; }
    public bool UseOverExtendedIndicator{get;set;}
    public int UseOverExtendedIndicatorDays { get; set; }
    public int UseOverExtendedIndicatorViolationThreshhold { get; set; }
    public double UseOverExtendedIndicatorMarginPercent { get; set; }
    public bool UseMaxPositionBucketWeight{get;set;}
    public double UseMaxPositionBucketWeightMaxWeight{get;set;}
		public bool UseCNN{get;set;}
		public String UseCNNHost{get;set;}
		public int UseCNNDayCount{get;set;}
    public double UseCNNRewardPercentDecimal{get;set;}

    public void DisplayHeader()
    {
      MDTrace.WriteLine(LogLevel.DEBUG, "Setting,Value");
    }
    public NVPCollection ToNVPCollection()
    {
      NVPCollection nvpCollection = new NVPCollection();
      nvpCollection.Add(new NVP("DayCount", DayCount.ToString()));
      nvpCollection.Add(new NVP("AnalysisDate", AnalysisDate.ToShortDateString()));
      nvpCollection.Add(new NVP("TradeDate", TradeDate.ToShortDateString()));
      nvpCollection.Add(new NVP("DailyReturnLimit", DailyReturnLimit.ToString()));
      nvpCollection.Add(new NVP("MovingAverageConstraintDays", MovingAverageConstraintDays.ToString()));
      nvpCollection.Add(new NVP("FallbackCandidateBestOf", FallbackCandidateBestOf.ToString()));
      nvpCollection.Add(new NVP("Benchmark", Benchmark.ToString()));
      nvpCollection.Add(new NVP("BenchmarkMovingAverageDays", BenchmarkMovingAverageDays.ToString()));
      nvpCollection.Add(new NVP("HoldingPeriod", HoldingPeriod.ToString()));
      nvpCollection.Add(new NVP("MaxPositions", MaxPositions.ToString()));
      nvpCollection.Add(new NVP("NoTradeSymbols", NoTradeSymbols.ToString()));
      nvpCollection.Add(new NVP("InitialCash", InitialCash.ToString()));
      nvpCollection.Add(new NVP("TargetBeta", TargetBeta.ToString()));
      nvpCollection.Add(new NVP("BetaMonths", BetaMonths.ToString()));
      nvpCollection.Add(new NVP("MarketCapLowerLimit", MarketCapLowerLimit.ToString()));
      nvpCollection.Add(new NVP("MaxBeta", MaxBeta.ToString()));
      nvpCollection.Add(new NVP("UseMaxBeta", UseMaxBeta.ToString()));
      nvpCollection.Add(new NVP("FallbackMaxAlloc", FallbackMaxAlloc.ToString()));
      nvpCollection.Add(new NVP("UseOverExtendedIndicator",UseOverExtendedIndicator.ToString()));
      nvpCollection.Add(new NVP("UseOverExtendedIndicatorDays",UseOverExtendedIndicatorDays.ToString()));
      nvpCollection.Add(new NVP("UseOverExtendedIndicatorViolationThreshhold",UseOverExtendedIndicatorViolationThreshhold.ToString()));
      nvpCollection.Add(new NVP("UseOverExtendedIndicatorMarginPercent",UseOverExtendedIndicatorMarginPercent.ToString()));
      nvpCollection.Add(new NVP("UseMaxPositionBucketWeight",UseMaxPositionBucketWeight.ToString()));
      nvpCollection.Add(new NVP("UseMaxPositionBucketWeightMaxWeight",UseMaxPositionBucketWeightMaxWeight.ToString()));
      nvpCollection.Add(new NVP("UseCNN",UseCNN.ToString()));
      nvpCollection.Add(new NVP("UseCNNHost",UseCNNHost.ToString()));
      nvpCollection.Add(new NVP("UseCNNDayCount",UseCNNDayCount.ToString()));
      nvpCollection.Add(new NVP("UseCNNRewardPercentDecimal",UseCNNRewardPercentDecimal.ToString()));
      return nvpCollection;
    }
    public static CMParams FromNVPCollection(NVPCollection nvpCollection)
    {
      CMParams cmParams=new CMParams();
      NVPDictionary nvpDictionary = nvpCollection.ToDictionary();
      cmParams.DayCount = nvpDictionary["DayCount"].Get<int>();
      cmParams.AnalysisDate = nvpDictionary["AnalysisDate"].Get<DateTime>();
      cmParams.AnalysisDate = nvpDictionary["TradeDate"].Get<DateTime>();
      cmParams.DailyReturnLimit = nvpDictionary["DailyReturnLimit"].Get<double>();
      cmParams.MovingAverageConstraintDays = nvpDictionary["MovingAverageConstraintDays"].Get<int>();
      cmParams.FallbackCandidateBestOf = nvpDictionary["FallbackCandidateBestOf"].Get<String>();
      cmParams.Benchmark = nvpDictionary["Benchmark"].Get<String>();
      cmParams.BenchmarkMovingAverageDays = nvpDictionary["BenchmarkMovingAverageDays"].Get<int>();
      cmParams.HoldingPeriod = nvpDictionary["HoldingPeriod"].Get<int>();
      cmParams.MaxPositions = nvpDictionary["MaxPositions"].Get<int>();
      cmParams.NoTradeSymbols = nvpDictionary["NoTradeSymbols"].Get<String>();
      cmParams.InitialCash = nvpDictionary["InitialCash"].Get<Double>();
      cmParams.TargetBeta = nvpDictionary["TargetBeta"].Get<Double>();
      cmParams.BetaMonths = nvpDictionary["BetaMonths"].Get<int>();
      cmParams.MarketCapLowerLimit = nvpDictionary["MarketCapLowerLimit"].Get<double>();
      cmParams.MaxBeta = nvpDictionary["MaxBeta"].Get<double>();
      cmParams.UseMaxBeta = nvpDictionary["UseMaxBeta"].Get<bool>();
      cmParams.FallbackMaxAlloc = nvpDictionary["FallbackMaxAlloc"].Get<double>();
      if(nvpDictionary.ContainsKey("UseOverExtendedIndicator"))
      {
        cmParams.UseOverExtendedIndicator=nvpDictionary["UseOverExtendedIndicator"].Get<bool>();
        cmParams.UseOverExtendedIndicatorDays=nvpDictionary["UseOverExtendedIndicatorDays"].Get<int>();
        cmParams.UseOverExtendedIndicatorViolationThreshhold=nvpDictionary["UseOverExtendedIndicatorViolationThreshhold"].Get<int>();
        cmParams.UseOverExtendedIndicatorMarginPercent=nvpDictionary["UseOverExtendedIndicatorMarginPercent"].Get<double>();
      }
      else
      {
        cmParams.UseOverExtendedIndicator=false;
        cmParams.UseOverExtendedIndicatorDays=0;
        cmParams.UseOverExtendedIndicatorViolationThreshhold=1;
        cmParams.UseOverExtendedIndicatorMarginPercent=1;
      }

      if(nvpDictionary.ContainsKey("UseMaxPositionBucketWeight"))
      {
        cmParams.UseMaxPositionBucketWeight=nvpDictionary["UseMaxPositionBucketWeight"].Get<bool>();
        cmParams.UseMaxPositionBucketWeightMaxWeight=nvpDictionary["UseMaxPositionBucketWeightMaxWeight"].Get<double>();
      }
      else
      {
        cmParams.UseMaxPositionBucketWeight=true;
        cmParams.UseMaxPositionBucketWeightMaxWeight=0.65;
      }
			if(nvpDictionary.ContainsKey("UseCNN"))
			{
			  cmParams.UseCNN=nvpDictionary["UseCNN"].Get<bool>();
				if(nvpDictionary.ContainsKey("UseCNNHost"))cmParams.UseCNNHost=nvpDictionary["UseCNNHost"].Get<String>();
				if(nvpDictionary.ContainsKey("UseCNNDayCount"))cmParams.UseCNNDayCount=nvpDictionary["UseCNNDayCount"].Get<int>();
        if(nvpDictionary.ContainsKey("UseCNNRewardPercentDecimal"))cmParams.UseCNNRewardPercentDecimal=nvpDictionary["UseCNNRewardPercentDecimal"].Get<double>();
			}
      return cmParams;
    }
    public void DisplayConfiguration()
    {                                                                
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("DayCount,{0}", DayCount));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("AnalysisDate,{0}", AnalysisDate));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("TradeDate,{0}", TradeDate));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("DailyReturnLimit,{0}", DailyReturnLimit));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("MovingAverageConstraintDays,{0}", MovingAverageConstraintDays));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("FallbackCandidateBestOf,{0}", FallbackCandidateBestOf));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Benchmark,{0}", Benchmark));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("BenchmarkMovingAverageDays,{0}", BenchmarkMovingAverageDays));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("HoldingPeriod,{0}", HoldingPeriod));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("MaxPositions,{0}", MaxPositions));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("NoTradeSymbols,{0}", NoTradeSymbols));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("InitialCash,{0}", InitialCash));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("TargetBeta,{0}", TargetBeta.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("BetaMonths,{0}", BetaMonths.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("MarketCapLowerLimit,{0}", MarketCapLowerLimit.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("UseMaxBeta,{0}", UseMaxBeta.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("MaxBeta,{0}", MaxBeta.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG, String.Format("FallbackMaxAlloc,{0}", FallbackMaxAlloc.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseOverExtendedIndicator,{0}",UseOverExtendedIndicator.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseOverExtendedIndicatorDays,{0}",UseOverExtendedIndicatorDays.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseOverExtendedIndicatorViolationThreshhold,{0}",UseOverExtendedIndicatorViolationThreshhold.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseOverExtendedIndicatorMarginPercent,{0}",UseOverExtendedIndicatorMarginPercent.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseMaxPositionBucketWeight,{0}",UseMaxPositionBucketWeight.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseMaxPositionBucketWeightMaxWeight,{0}",UseMaxPositionBucketWeightMaxWeight.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseCNN,{0}",UseCNN.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseCNNHost,{0}",UseCNNHost.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseCNNDayCount,{0}",UseCNNDayCount.ToString()));
      MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseCNNRewardPercentDecimal,{0}",UseCNNRewardPercentDecimal.ToString()));
    }
  }
}
