This was causing an issue in the SharpeRatioGenerator whereby the SharpeRatio was not being calculated correctly where the asof date would fall on a weekend of holiday. Also, added a ReasonCategory to the CMCanidate as well as a Violation summary line in the model output to show where violations occur. Had I implemented this previously I might have detected the SharpeRatio issue sooner. Also added GetFundamentalMaxDateTop in the FundamentalDA which I used during debugging but is not currently being used anywhere.
199 lines
15 KiB
C#
199 lines
15 KiB
C#
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()));
|
|
}
|
|
}
|
|
}
|