Files
Sean 2882559651 Fix GetMonthlyPrices in Prices. It was not correctly returning monthly prices.
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.
2025-02-02 14:59:14 -05:00

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()));
}
}
}