diff --git a/.gitignore b/.gitignore index 2b81057..eda5b4e 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ obj /bin/Debug/*.log /bin /.vs +/gitdiff.bat +/HedgeCashBalanceMarginStrategy +/Scraps diff --git a/Database/DividendCorrections202050609.xlsx b/Database/DividendCorrections202050609.xlsx new file mode 100644 index 0000000..c87f30e Binary files /dev/null and b/Database/DividendCorrections202050609.xlsx differ diff --git a/Database/Transaction_History.xlsm b/Database/Transaction_History.xlsm new file mode 100644 index 0000000..a675f54 Binary files /dev/null and b/Database/Transaction_History.xlsm differ diff --git a/Database/VSTCX_Contributions.xlsx b/Database/VSTCX_Contributions.xlsx new file mode 100644 index 0000000..61d2447 Binary files /dev/null and b/Database/VSTCX_Contributions.xlsx differ diff --git a/Database/users.sql b/Database/users.sql new file mode 100644 index 0000000..21d771a --- /dev/null +++ b/Database/users.sql @@ -0,0 +1,12 @@ +CREATE TABLE users +( + username VARCHAR(128) NOT NULL, + salt VARCHAR(128) NOT NULL, + hash VARCHAR(128) NOT NULL, + created_by VARCHAR(128) NOT NULL DEFAULT user(), + created_on DATETIME NOT NULL DEFAULT curdate(), + modified_by VARCHAR(128), + modified_on DATETIME, + PRIMARY KEY (username) +) +; diff --git a/MarketDataLib/Generator/MGSHMomentum/MGSHPricingException.cs b/MarketDataLib/Generator/MGSHMomentum/MGSHPricingException.cs new file mode 100644 index 0000000..45c405a --- /dev/null +++ b/MarketDataLib/Generator/MGSHMomentum/MGSHPricingException.cs @@ -0,0 +1,66 @@ +using MarketData.Utils; +using System; +using System.Collections.Generic; + +namespace MarketData.Generator.MGSHMomentum +{ + public class MGSHPricingExceptions:List + { + public NVPCollections ToNVPCollections() + { + NVPCollections nvpCollections=new NVPCollections(); + foreach(MGSHPricingException pricingException in this) + { + nvpCollections.Add(pricingException.ToNVPCollection()); + } + return nvpCollections; + } + public static MGSHPricingExceptions FromNVPCollections(NVPCollections nvpCollections) + { + MGSHPricingExceptions pricingExcpetions=new MGSHPricingExceptions(); + foreach(NVPCollection nvpCollection in nvpCollections) + { + pricingExcpetions.Add(MGSHPricingException.FromNVPCollection(nvpCollection)); + } + return pricingExcpetions; + } + public void AddFromNVPCollection(NVPCollection nvpCollection) + { + Add(MGSHPricingException.FromNVPCollection(nvpCollection)); + } + } + public class MGSHPricingException + { + public MGSHPricingException() + { + } + public MGSHPricingException(MGSHPricingException pricingException) + { + this.Symbol=pricingException.Symbol; + this.ExceptionCount=pricingException.ExceptionCount; + } + public MGSHPricingException(String symbol,int exceptionCount) + { + this.Symbol=symbol; + this.ExceptionCount=exceptionCount; + } + public String Symbol { get; set; } + public int ExceptionCount { get; set; } + public virtual NVPCollection ToNVPCollection() + { + NVPCollection nvpCollection=new NVPCollection(); + nvpCollection.Add(new NVP("Symbol",Symbol.ToString())); + nvpCollection.Add(new NVP("ExceptionCount",ExceptionCount.ToString())); + return nvpCollection; + } + public static MGSHPricingException FromNVPCollection(NVPCollection nvpCollection) + { + MGSHPricingException pricingException=new MGSHPricingException(); + + NVPDictionary nvpDictionary=nvpCollection.ToDictionary(); + pricingException.Symbol=nvpDictionary["Symbol"].Get(); + pricingException.ExceptionCount=nvpDictionary["ExceptionCount"].Get(); + return pricingException; + } + } +} diff --git a/MarketDataLib/Generator/Model/RealtimeGainLoss.cs b/MarketDataLib/Generator/Model/RealtimeGainLoss.cs new file mode 100644 index 0000000..07f80d1 --- /dev/null +++ b/MarketDataLib/Generator/Model/RealtimeGainLoss.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace MarketData.Generator.Model +{ + public class RealtimeGainLoss + { + public double Exposure{get;set;} + public double MarketValue{get;set;} + public double GainLoss{get{return MarketValue-Exposure;}} + public double GainLossPercent{get{return Exposure==0?0:(MarketValue-Exposure)/Exposure;}} + } +} diff --git a/MarketDataLib/Generator/RSIGenerator.cs.bak b/MarketDataLib/Generator/RSIGenerator.cs.bak new file mode 100644 index 0000000..5637b17 --- /dev/null +++ b/MarketDataLib/Generator/RSIGenerator.cs.bak @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Serialization; +using System.Text; +using System.Threading.Tasks; +using MarketData.MarketDataModel; +using MarketData.Utils; +using MarketData.DataAccess; + +namespace MarketData.Generator +{ + public class RSIGenerator + { + private RSIGenerator() + { + } + public static RSICollection GenerateRSI(String symbol,int priceCount,int rsiDayCount=14) + { + if(priceCount=0;index--) + { + Price price=prices[index]; + RSIElement rsiElement=new RSIElement(); + rsiElement.Symbol=price.Symbol; + rsiElement.RSIDays=rsiDayCount; + rsiElement.Date=price.Date; + rsiElement.Close=price.Close; + if(index==prices.Count-1)continue; + rsiElement.Change=price.Close-prices[index+1].Close; + if(rsiElement.Change<0){rsiElement.Loss=Math.Abs(rsiElement.Change);rsiElement.Gain=0.00;} + else if(rsiElement.Change>0){rsiElement.Gain=rsiElement.Change;rsiElement.Loss=0.00;} + else{rsiElement.Loss=0.00;rsiElement.Gain=0.00;} + rsiCollection.Add(rsiElement); + } + RSICollection topCollection=rsiCollection.Top(rsiDayCount,1); + rsiCollection[rsiDayCount].AverageGain=topCollection.AverageGain(); + rsiCollection[rsiDayCount].AverageLoss=topCollection.AverageLoss(); + if(0.00==rsiCollection[rsiDayCount].AverageLoss) + { + rsiCollection[rsiDayCount].RS=0.00; + rsiCollection[rsiDayCount].RSI=100.00; + } + else + { + rsiCollection[rsiDayCount].RS=rsiCollection[rsiDayCount].AverageGain/rsiCollection[rsiDayCount].AverageLoss; + rsiCollection[rsiDayCount].RSI=100.00-(100.00/(1.00+rsiCollection[rsiDayCount].RS)); + } + for(int index=rsiDayCount+1;index=0;index--) + { + Price price=prices[index]; + RSIElement rsiElement=new RSIElement(); + rsiElement.Symbol=price.Symbol; + rsiElement.RSIDays=rsiDayCount; + rsiElement.Date=price.Date; + rsiElement.Close=price.Close; + if(index==prices.Count-1)continue; + rsiElement.Change=price.Close-prices[index+1].Close; + if(rsiElement.Change<0){rsiElement.Loss=Math.Abs(rsiElement.Change);rsiElement.Gain=0.00;} + else if(rsiElement.Change>0){rsiElement.Gain=rsiElement.Change;rsiElement.Loss=0.00;} + else{rsiElement.Loss=0.00;rsiElement.Gain=0.00;} + rsiCollection.Add(rsiElement); + } + RSICollection topCollection=rsiCollection.Top(rsiDayCount,1); + rsiCollection[rsiDayCount].AverageGain=topCollection.AverageGain(); + rsiCollection[rsiDayCount].AverageLoss=topCollection.AverageLoss(); + if(0.00==rsiCollection[rsiDayCount].AverageLoss) + { + rsiCollection[rsiDayCount].RS=0.00; + rsiCollection[rsiDayCount].RSI=100.00; + } + else + { + rsiCollection[rsiDayCount].RS=rsiCollection[rsiDayCount].AverageGain/rsiCollection[rsiDayCount].AverageLoss; + rsiCollection[rsiDayCount].RSI=100.00-(100.00/(1.00+rsiCollection[rsiDayCount].RS)); + } + for(int index=rsiDayCount+1;index + /// CMCANDIDATELASTRESORT /TRADEDATE: + /// + /// + public static void RunCMCandidateLastResort(String[] args) + { + CMParams cmParams = new CMParams(); + List candidates = Utility.ToList(cmParams.FallbackCandidateBestOf); + CommandArgs commandArgs = new CommandArgs(args); + if (!commandArgs.Has("TRADEDATE")) { MDTrace.WriteLine(LogLevel.DEBUG, "TRADEDATE required"); return; } + CMCandidate cmCandidate = CMCandidateGenerator.GetFallbackCandidateOfLastResort(candidates, commandArgs.Coalesce("TRADEDATE"), commandArgs.Coalesce("TRADEDATE"), cmParams); + if (null == cmCandidate) { MDTrace.WriteLine(LogLevel.DEBUG, "Unable to determine candidate of last resort."); return; } + foreach (String candidate in candidates) + { + MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Candidate examined..{0}", candidate)); + } + MDTrace.WriteLine(LogLevel.DEBUG, String.Format("Best candidate is {0}", cmCandidate.Symbol)); + } + + /// + /// CMGAINLOSS /SESSIONFILE:{PATHSESSIONFILE} (i.e.) CMGAINLOSS /SESSIONFILE:C:\boneyard\marketdata\bin\Debug\saferun\CM20191031.txt"); + /// + /// + public static void RunCMGainLoss(String[] args) + { + CommandArgs commandArgs=new CommandArgs(args); + if(!commandArgs.Has("SESSIONFILE")) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Missing SESSIONFILE")); return; } + CMMomentumBacktest cmBacktest=new CMMomentumBacktest(); + cmBacktest.DisplayGainLoss(commandArgs.Coalesce("SESSIONFILE")); + } + + /// + /// CMSESSION /SESSIONFILE: + /// + /// + public static void RunCMSession(String[] args) + { + CommandArgs commandArgs = new CommandArgs(args); + if (!commandArgs.Has("SESSIONFILE")) + { + MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Missing SESSIONFILE")); + return; + } + CMMomentumBacktest cmBacktest = new CMMomentumBacktest(); + cmBacktest.DisplaySession(commandArgs.Coalesce("SESSIONFILE")); + } + + /// + /// RUNCMBACKTEST /STARTDATE: /MAXPOSITIONS: /INITIALCASH: /HOLDINGPERIOD: /{USEBINBASEDPOSITIONSIZING}: /{USEBINBASEDPOSITIONSIZINGNUMBINS}: /{TARGETBETA}: /{ENDDATE}: /SESSIONFILE: /{USECNN}: /{USECNNHOST}: /{USECNNDAYCOUNT}: + /// + /// + public static void RunCMMomentum(String[] args) + { + CommandArgs commandArgs=new CommandArgs(args); + if(!commandArgs.Has("STARTDATE,MAXPOSITIONS,INITIALCASH,HOLDINGPERIOD")) + { + if(!commandArgs.Has("STARTDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"Missing STARTDATE"); + if(!commandArgs.Has("MAXPOSITIONS")) MDTrace.WriteLine(LogLevel.DEBUG,"Missing MAXPOSITIONS"); + if(!commandArgs.Has("INITIALCASH")) MDTrace.WriteLine(LogLevel.DEBUG,"Missing INITIALCASH"); + if(!commandArgs.Has("HOLDINGPERIOD")) MDTrace.WriteLine(LogLevel.DEBUG,"Missing HOLDINGPERIOD"); + return; + } + + CMParams cmParams=new CMParams(); + cmParams.AnalysisDate=commandArgs.Get("STARTDATE"); + cmParams.MaxPositions=commandArgs.Get("MAXPOSITIONS"); + cmParams.InitialCash=commandArgs.Get("INITIALCASH"); + cmParams.HoldingPeriod=commandArgs.Get("HOLDINGPERIOD"); + + if(commandArgs.Has("USECNN")) + { + if(!commandArgs.Has("USECNNCLIENT,USECNNDAYCOUNT")) + { + MDTrace.WriteLine(LogLevel.DEBUG,"Missing USECNNCLIENT, USECNNDAYCOUNT"); + return; + } + cmParams.UseCNN=true; + cmParams.UseCNNHost=commandArgs.Get("USECNNHOST"); + cmParams.UseCNNDayCount=commandArgs.Get("USECNNDAYCOUNT"); + if(commandArgs.Has("USECNNREWARDPERCENTDECIMAL"))cmParams.UseCNNRewardPercentDecimal=commandArgs.Get("USECNNREWARDPERCENTDECIMAL"); + } + + if(commandArgs.Has("USEOVEREXTENDEDINDICATOR")) + { + if(!commandArgs.Has("USEOVEREXTENDEDINDICATORDAYS,USEOVEREXTENDEDINDICATORVIOLATIONTHRESHHOLD,USEOVEREXTENDEDINDICATORMARGINPERCENT")) + { + MDTrace.WriteLine(LogLevel.DEBUG,"Missing USEOVEREXTENDEDINDICATORDAYS, USEOVEREXTENDEDINDICATORVIOLATIONTHRESHHOLD, USEOVEREXTENDEDINDICATORMARGINPERCENT"); + return; + } + cmParams.UseOverExtendedIndicator=commandArgs.Get("USEOVEREXTENDEDINDICATOR"); + cmParams.UseOverExtendedIndicatorDays=commandArgs.Get("USEOVEREXTENDEDINDICATORDAYS"); + cmParams.UseOverExtendedIndicatorViolationThreshhold=commandArgs.Get("USEOVEREXTENDEDINDICATORVIOLATIONTHRESHHOLD"); + cmParams.UseOverExtendedIndicatorMarginPercent=commandArgs.Get("USEOVEREXTENDEDINDICATORMARGINPERCENT"); + } + + + if(commandArgs.Has("USEMAXPOSITIONBUCKETWEIGHT")) // UseMaxPositionBucketWeight + { + if(!commandArgs.Has("USEMAXPOSITIONBUCKETWEIGHTMAXWEIGHT")) // UseMaxPositionBucketWeightMaxWeight + { + MDTrace.WriteLine(LogLevel.DEBUG,"Missing USEMAXPOSITIONBUCKETWEIGHTMAXWEIGHT"); + return; + } + cmParams.UseMaxPositionBucketWeight=commandArgs.Get("USEMAXPOSITIONBUCKETWEIGHT"); + cmParams.UseMaxPositionBucketWeightMaxWeight=commandArgs.Get("USEMAXPOSITIONBUCKETWEIGHTMAXWEIGHT"); + } + else + { + cmParams.UseMaxPositionBucketWeight=false; + cmParams.UseMaxPositionBucketWeightMaxWeight=0; + } + + if(commandArgs.Has("TARGETBETA"))cmParams.TargetBeta=commandArgs.Get("TARGETBETA"); + else cmParams.TargetBeta=1.00; + + DateTime endDate=DateTime.Now; + String pathSessionFileName=commandArgs.Coalesce("SESSIONFILE",null); + if(null!=pathSessionFileName) pathSessionFileName=pathSessionFileName.Trim(); + cmParams.DisplayHeader(); + + CMMomentumBacktest backtestMomentum=new CMMomentumBacktest(); + List results=new List(); + results.Add(backtestMomentum.PerformBacktest(cmParams.AnalysisDate,endDate,pathSessionFileName,cmParams)); + } + } +} diff --git a/ModelHelper/CMTrendHelper.cs b/ModelHelper/CMTrendHelper.cs new file mode 100644 index 0000000..43cbc7f --- /dev/null +++ b/ModelHelper/CMTrendHelper.cs @@ -0,0 +1,185 @@ +using MarketData.Generator.CMTrend; +using MarketData.Utils; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace MarketData.ModelHelper +{ + public static class CMTrendHelper + { + public static void HandleCMTSession(CommandArgs commandArgs) + { + if (!commandArgs.Has("SESSIONFILE")) {MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Missing SESSIONFILE"));return;} + CMTTrendModel trendModel=new CMTTrendModel(); + trendModel.DisplaySession(commandArgs.Coalesce("SESSIONFILE")); + } + + public static void HandleRunCMTrend(CommandArgs commandArgs) + { + String mode; + + if(!commandArgs.Has("MODE")) + { + if(!commandArgs.Has("MODE")) MDTrace.WriteLine(LogLevel.DEBUG,"MODE is a required paramater."); + MDTrace.WriteLine(LogLevel.DEBUG,"RUNMMTREND /MODE:DAILY|BACKTEST|RUNTRENDTEMPLATE|ANALYZE|DISPLAY|CLOSEPOSITION /SELLDATE:{CLOSEPOSITION} /PRICE:{CLOSEPOSITION} /SYMBOL:{for mode ANALYZE,CLOSEPOSITION} /TRADEDATE:{for mode DAILY,RUNTRENDTEMPLATE,ANALYZE,CLOSEPOSITION) /STARTDATE:(for mode BACKTEST) /ENDDATE:(for mode BACKTEST) /INITIALCASH: /SESSIONFILE: MAXOPENPOSITIONS: /MAXDAILYPOSITIONS: Runs Mark Minervini trend"); + return; + } + mode=commandArgs.Get("MODE"); + if("ENTRYTEST".Equals(mode)) + { + CMTParams cmtParams=new CMTParams(); + if(!commandArgs.Has("SYMBOL")||!commandArgs.Has("STARTDATE")) + { + if(!commandArgs.Contains("SYMBOL")) MDTrace.WriteLine(LogLevel.DEBUG,"SYMBOL is a required parameter when MODE=ENTRYTEST"); + if(!commandArgs.Contains("STARTDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"STARTDATE is a required parameter when MODE=ENTRYTEST"); + return; + } + CMTTrendModel trendModel=new CMTTrendModel(); + trendModel.EntryTest(commandArgs.Get("SYMBOL"),commandArgs.Get("STARTDATE")); + } + else if("CLOSEPOSITION".Equals(mode)) + { + CMTParams cmtParams=new CMTParams(); + if(!commandArgs.Has("PURCHASEDATE,SYMBOL,SESSIONFILE,PRICE,SELLDATE")) + { + if(!commandArgs.Contains("PURCHASEDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"PURCHASEDATE is a required parameter when MODE=CLOSEPOSITION"); + if(!commandArgs.Contains("SYMBOL")) MDTrace.WriteLine(LogLevel.DEBUG,"SYMBOL is a required parameter when MODE=CLOSEPOSITION"); + if(!commandArgs.Contains("SESSIONFILE")) MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE is a required parameter when MODE=CLOSEPOSITION"); + if(!commandArgs.Contains("PRICE")) MDTrace.WriteLine(LogLevel.DEBUG,"PRICE is a required parameter when MODE=CLOSEPOSITION"); + if(!commandArgs.Contains("SELLDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"SELLDATE is a required parameter when MODE=CLOSEPOSITION"); + return; + } + CMTTrendModel trendModel=new CMTTrendModel(); + trendModel.ClosePosition(commandArgs.Get("SYMBOL"),commandArgs.Get("PURCHASEDATE"),commandArgs.Get("SELLDATE"),commandArgs.Get("PRICE"),commandArgs.Get("SESSIONFILE")); + } + else if("DAILY".Equals(mode)) + { + CMTParams cmtParams=new CMTParams(); + if(!commandArgs.Has("TRADEDATE,SESSIONFILE")) + { + if(!commandArgs.Contains("TRADEDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"TRADEDATE is a required parameter when MODE=DAILY"); + if(!commandArgs.Contains("SESSIONFILE")) MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE is a required parameter when MODE=DAILY"); + return; + } + if(commandArgs.Contains("INITIALCASH")) cmtParams.InitialCash=commandArgs.Get("INITIALCASH"); + if(commandArgs.Contains("MAXDAILYPOSITIONS")) cmtParams.MaxDailyPositions=commandArgs.Get("MAXDAILYPOSITIONS"); + if(commandArgs.Contains("MAXOPENPOSITIONS")) cmtParams.MaxOpenPositions=commandArgs.Get("MAXOPENPOSITIONS"); + + if(commandArgs.Has("ONLYTRADESYMBOLS")) cmtParams.OnlyTradeSymbols=commandArgs.Get("ONLYTRADESYMBOLS"); + + if(commandArgs.Contains("POSITIONRISKPERCENTDECIMAL")) + { + cmtParams.PositionRiskPercentDecimal=commandArgs.Get("POSITIONRISKPERCENTDECIMAL"); + } + + if(commandArgs.Contains("ENTRYTYPE")) + { + List entryTypes=Utility.ToList(commandArgs.Get("ENTRYTYPE")); + List constraints=new List { "OVEREXTENDED","MVP","NARROWRANGE","MACD","PRICETREND","VOLUMETREND" }; + bool results=entryTypes.All(i => constraints.ContainsIgnoreCase(i)); + if(!results) + { + MDTrace.WriteLine(LogLevel.DEBUG,"ENTRYTYPE must consist of one or more OVEREXTENDED, MVP, NarrowRange, MACD, PriceTrend, VolumeTrend"); + return; + } + cmtParams.EntryType=commandArgs.Get("ENTRYTYPE"); + } + CMTTrendModel trendModel=new CMTTrendModel(); + + if(commandArgs.Contains("USETRADEONLYSECTORS")) + { + cmtParams.UseTradeOnlySectors=commandArgs.Get("USETRADEONLYSECTORS"); + if(cmtParams.UseTradeOnlySectors) + { + cmtParams.UseTradeOnlySectorsSectors=commandArgs.Get("USETRADEONLYSECTORSSECTORS"); + } + } + CMTTrendModelResult result=trendModel.RunDaily(commandArgs.Get("TRADEDATE"),commandArgs.Get("SESSIONFILE"),cmtParams); + } + else if("BACKTEST".Equals(mode)) + { + CMTParams cmtParams=new CMTParams(); + bool sellAtEndOfSimulation=true; + if(!commandArgs.Has("STARTDATE,ENDDATE,SESSIONFILE")) + { + if(!commandArgs.Contains("STARTDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"STARTDATE is a required parameter"); + if(!commandArgs.Contains("ENDDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"ENDDATE is a required parameter"); + if(!commandArgs.Contains("SESSIONFILE")) MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE is a required parameter"); + return; + } + + CMTTrendModel trendModel=new CMTTrendModel(); + + if(commandArgs.Contains("USETRADEONLYSECTORS")) + { + cmtParams.UseTradeOnlySectors=commandArgs.Get("USETRADEONLYSECTORS"); + if(cmtParams.UseTradeOnlySectors) + { + cmtParams.UseTradeOnlySectorsSectors=commandArgs.Get("USETRADEONLYSECTORSSECTORS"); + } + } + + if(commandArgs.Contains("USEPROFITMAXIMIZATION")) + { + cmtParams.UseProfitMaximization=commandArgs.Get("USEPROFITMAXIMIZATION"); + if(commandArgs.Contains("USEPROFITMAXIMIZATIONEXPRESSION")) + { + cmtParams.UseProfitMaximizationExpression=commandArgs.Get("USEPROFITMAXIMIZATIONEXPRESSION"); + } + } + + if(commandArgs.Contains("MAXDAILYPOSITIONS")) cmtParams.MaxDailyPositions=commandArgs.Get("MAXDAILYPOSITIONS"); + if(commandArgs.Contains("MAXOPENPOSITIONS")) cmtParams.MaxOpenPositions=commandArgs.Get("MAXOPENPOSITIONS"); + if(commandArgs.Contains("BENCHMARKMOVINGAVERAGEDAYS")) cmtParams.BenchmarkMovingAverageDays=commandArgs.Get("BENCHMARKMOVINGAVERAGEDAYS"); + if(commandArgs.Contains("BENCHMARKMOVINGAVERAGEHORIZON")) cmtParams.BenchmarkMovingAverageHorizon=commandArgs.Get("BENCHMARKMOVINGAVERAGEHORIZON"); + + if(commandArgs.Has("ONLYTRADESYMBOLS")) cmtParams.OnlyTradeSymbols=commandArgs.Get("ONLYTRADESYMBOLS"); + + if(commandArgs.Contains("POSITIONRISKPERCENTDECIMAL")) + { + cmtParams.PositionRiskPercentDecimal=commandArgs.Get("POSITIONRISKPERCENTDECIMAL"); + } + + if(commandArgs.Contains("ENTRYTYPE")) + { + List entryTypes=Utility.ToList(commandArgs.Get("ENTRYTYPE")); + List constraints=new List { "OVEREXTENDED","MVP","NARROWRANGE","MACD","PRICETREND","VOLUMETREND" }; + bool results=entryTypes.All(i => constraints.ContainsIgnoreCase(i)); + if(!results) + { + MDTrace.WriteLine(LogLevel.DEBUG,"ENTRYTYPE must consist of one or more OVEREXTENDED, MVP, NarrowRange, MACD, PriceTrend, VolumeTrend"); + return; + } + cmtParams.EntryType=commandArgs.Get("ENTRYTYPE"); + } + if(commandArgs.Contains("SELLATENDOFSIMULATION")) + { + sellAtEndOfSimulation=commandArgs.Get("SELLATENDOFSIMULATION"); + } + CMTTrendModelResult result=trendModel.RunBacktestMode(commandArgs.Get("STARTDATE"),commandArgs.Get("ENDDATE"),sellAtEndOfSimulation,commandArgs.Get("SESSIONFILE"),cmtParams); + } + else if("DISPLAY".Equals(mode)) + { + if(!commandArgs.Contains("SESSIONFILE")) { MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE is a required parameter"); return; } + CMTTrendModel trendModel=new CMTTrendModel(); + trendModel.DisplaySession(commandArgs.Get("SESSIONFILE")); + } + else if("RUNTRENDTEMPLATE".Equals(mode)) + { + if(!commandArgs.Contains("TRADEDATE")) + { + MDTrace.WriteLine(LogLevel.DEBUG,"TRADEDATE is a required parameter when MODE=DAILY"); + return; + } + CMTTrendModel trendModel=new CMTTrendModel(); + trendModel.RunTrendTemplate(commandArgs.Get("TRADEDATE")); + } + else + { + MDTrace.WriteLine(LogLevel.DEBUG,"RUNCMTREND /MODE:DAILY|BACKTEST /TRADEDATE:{for mode DAILY) /STARTDATE:(for mode BACKTEST) /ENDDATE:(for mode BACKTEST) /INITIALCASH: /SESSIONFILE: /MAXPOSITIONS Runs Mark Minervini trend"); + } + return; + } + } +} diff --git a/ModelHelper/MGMomentumHelper.cs b/ModelHelper/MGMomentumHelper.cs new file mode 100644 index 0000000..73f7b06 --- /dev/null +++ b/ModelHelper/MGMomentumHelper.cs @@ -0,0 +1,137 @@ +using MarketData.Generator.Momentum; +using System; +using System.Collections.Generic; + +namespace MarketData.ModelHelper +{ + public static class MGMomentumHelper + { + /// + /// RUNMOMENTUM /STARTDATE: /MAXPOSITIONS: + /// + /// + public static void RunMomentum(CommandArgs commandArgs) + { + if (!commandArgs.Has("STARTDATE,MAXPOSITIONS")) return; + DateTime analysisDate = commandArgs.Coalesce("STARTDATE"); + int maxPositions = commandArgs.Coalesce("MAXPOSITIONS"); + MGConfiguration config = new MGConfiguration(); + MomentumCandidates momentumCandidates = MomentumGenerator.GenerateMomentum(analysisDate, config); + MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0}", MomentumCandidate.Header())); + for (int index = 0; index < momentumCandidates.Count; index++) + { + MomentumCandidate momentumCandidate = momentumCandidates[index]; + MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0}", momentumCandidate.ToString())); + } + } + + /// + /// MGLIQUIDATE /SESSIONFILE: /TRADEDATE: + /// + /// + public static void RunMGLiquidate(CommandArgs commandArgs) + { + DateTime? tradeDate = null; + if (!commandArgs.Has("SESSIONFILE")) return; + if (commandArgs.Has("TRADEDATE")) tradeDate = commandArgs.Coalesce("TRADEDATE"); + MomentumBacktest momentumBacktest = new MomentumBacktest(); + momentumBacktest.MGLiquididate(commandArgs.Coalesce("SESSIONFILE"), tradeDate); + } + + /// + /// MGGAINLOSS /SESSIONFILE:{PATHSESSIONFILE} (i.e.) MGGAINLOSS /SESSIONFILE:C:\boneyard\marketdata\bin\Debug\saferun\MG20180131.txt"); + /// + /// + public static void RunMGGainLoss(CommandArgs commandArgs) + { + if(!commandArgs.Has("SESSIONFILE")) { MDTrace.WriteLine(LogLevel.DEBUG,"Missing SESSIONFILE"); return; } + MomentumBacktest momentumBacktest = new MomentumBacktest(); + MomentumBacktest.DisplayGainLoss(commandArgs.Coalesce("SESSIONFILE")); + } + /// + /// MGSESSION /SESSIONFILE: + /// + /// + public static void RunMGSession(CommandArgs commandArgs) + { + if(!commandArgs.Has("SESSIONFILE")) { MDTrace.WriteLine(LogLevel.DEBUG,"Missing SESSIONFILE"); return; } + MomentumBacktest momentumBacktest = new MomentumBacktest(); + momentumBacktest.DisplaySession(commandArgs.Coalesce("SESSIONFILE")); + } + + /// + /// RUNBACKTEST /STARTDATE: /MAXPOSITIONS: /INITIALCASH: /HOLDINGPERIOD: /{ENDDATE}: /{SESSIONFILE}: + /// + /// + public static void RunBacktest(CommandArgs commandArgs) + { + MGConfiguration mgParams=new MGConfiguration(); + if (!commandArgs.Has("STARTDATE,MAXPOSITIONS,INITIALCASH,HOLDINGPERIOD")) + { + if (!commandArgs.Has("STARTDATE")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing STARTDATE"); + if (!commandArgs.Has("MAXPOSITIONS")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing MAXPOSITIONS"); + if (!commandArgs.Has("INITIALCASH")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing INITIALCASH"); + if (!commandArgs.Has("HOLDINGPERIOD")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing HOLDINGPERIOD"); + return; + } + mgParams.MaxPositions=commandArgs.Coalesce("MAXPOSITIONS"); + mgParams.InitialCash=commandArgs.Coalesce("INITIALCASH"); + mgParams.HoldingPeriod=commandArgs.Coalesce("HOLDINGPERIOD"); + + if(commandArgs.Has("INCLUDETRADEMASTERFORSYMBOLSHELD")) + { + mgParams.IncludeTradeMasterForSymbolsHeld=commandArgs.Get("INCLUDETRADEMASTERFORSYMBOLSHELD"); + } + + if(commandArgs.Has("USESTOCHASTICS")) + { + mgParams.UseStochastics=commandArgs.Coalesce("USESTOCHASTICS",true); + } + + if(commandArgs.Has("USECALCBETA")) + { + mgParams.UseCalcBeta=commandArgs.Coalesce("USECALCBETA",true); + } + +// ** M A C D + if(commandArgs.Has("USEMACD")) + { + mgParams.UseMACD=commandArgs.Coalesce("USEMACD",true); + } + if(commandArgs.Has("MACDREJECTSTRONGSELLSIGNALS")) + { + mgParams.MACDRejectStrongSellSignals=commandArgs.Coalesce("MACDREJECTSTRONGSELLSIGNALS",true); + } + if(commandArgs.Has("MACDREJECTWEAKSELLSIGNALS")) + { + mgParams.MACDRejectWeakSellSignals=commandArgs.Coalesce("MACDREJECTWEAKSELLSIGNALS",true); + } + if(commandArgs.Has("MACDSIGNALDAYS")) + { + mgParams.MACDSignalDays=commandArgs.Coalesce("MACDSIGNALDAYS",mgParams.MACDSignalDays); + } + if(commandArgs.Has("MACDSETUP")) + { + mgParams.MACDSetup=commandArgs.Coalesce("MACDSETUP",mgParams.MACDSetup); + } +// ** + QualityIndicator qualityIndicator=new QualityIndicator(QualityIndicator.QualityType.IDIndicator); + if(commandArgs.Has("QUALITYINDICATORTYPE")) qualityIndicator.Quality=QualityIndicator.ToQuality(commandArgs.Coalesce("QUALITYINDICATORTYPE","IDINDICATOR")); + mgParams.QualityIndicatorType=qualityIndicator.ToString(); + + mgParams.UseLowSlopeBetaCheck=true; + if(commandArgs.Has("USELOWSLOPEBETACHECK")) mgParams.UseLowSlopeBetaCheck=commandArgs.Coalesce("USELOWSLOPEBETACHECK",true); + + DateTime startDate = commandArgs.Coalesce("STARTDATE"); + DateTime endDate=commandArgs.Coalesce("ENDDATE",new DateTime()); + + String pathSessionFileName = commandArgs.Coalesce("SESSIONFILE", null); + if(null!=pathSessionFileName)pathSessionFileName=pathSessionFileName.Trim(); + + mgParams.DisplayHeader(); + List results=new List(); + MomentumBacktest backtestMomentum=new MomentumBacktest(); + results.Add(backtestMomentum.PerformBacktest(startDate,endDate,pathSessionFileName,mgParams)); + } + } +} diff --git a/ModelHelper/MGSHMomentumHelper.cs b/ModelHelper/MGSHMomentumHelper.cs new file mode 100644 index 0000000..7f68d12 --- /dev/null +++ b/ModelHelper/MGSHMomentumHelper.cs @@ -0,0 +1,170 @@ +using MarketData.Generator.MGSHMomentum; +using MarketData.Utils; +using System; +using System.Collections.Generic; +using System.IO; + +namespace MarketData.ModelHelper +{ + public static class MGSHMomentumHelper + { + public static void HandleMGSHSession(String[] args) + { + CommandArgs commandArgs = new CommandArgs(args); + if(!commandArgs.Has("SESSIONFILE")) + { + MDTrace.WriteLine(LogLevel.DEBUG,"Missing SESSIONFILE"); + return; + } + MGSHMomentumBacktest momentumBacktest = new MGSHMomentumBacktest(); + momentumBacktest.DisplaySession(commandArgs.Coalesce("SESSIONFILE")); + } + + public static void HandleMGSHRunDaily(String[] args) + { + DateGenerator dateGenerator = new DateGenerator(); + CommandArgs commandArgs = new CommandArgs(args); + if(!commandArgs.Has("SESSIONFILE,TRADEDATE")) + { + MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE and TRADEDATE are required parameters."); + return; + } + DateTime tradeDate = commandArgs.Get("TRADEDATE"); + + if(!dateGenerator.IsMarketOpen(tradeDate)) + { + MDTrace.WriteLine(LogLevel.DEBUG,$"TRADEDATE {tradeDate.ToShortDateString()} is not a trading date."); + return; + } + + DateTime endDate = dateGenerator.FindNextBusinessDay(tradeDate); // UpdateDaily will not process the endDate (i.e.) while(tradeDate("SESSIONFILE"); + pathSessionFile = pathSessionFile.Trim(); + if(!File.Exists(pathSessionFile)) + { + MDTrace.WriteLine(LogLevel.DEBUG,$"The specified file '{pathSessionFile}' does not exist."); + return; + } + + MGSHMomentumBacktest momentumBacktest = new MGSHMomentumBacktest(); + + if(!dateGenerator.IsMarketOpen(tradeDate)) + { + Console.WriteLine(String.Format("The market is closed today, please confirm Y/N:{0}?",tradeDate.ToShortDateString())); + String result=Console.ReadLine(); + if(null==result||!(result.ToUpper().Equals("Y")||result.ToUpper().Equals("YES")))return; + } + + MGSHBacktestResult backtestResult = momentumBacktest.UpdateDaily(tradeDate, endDate, DateTime.Now, pathSessionFile); + } + + public static void HandleMGSHRunBacktest(String[] args) + { + CommandArgs commandArgs = new CommandArgs(args); + MGSHConfiguration mgParams=new MGSHConfiguration(); + if (!commandArgs.Has("STARTDATE,MAXPOSITIONS,INITIALCASH,HOLDINGPERIOD")) + { + if (!commandArgs.Has("STARTDATE")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing STARTDATE"); + if (!commandArgs.Has("MAXPOSITIONS")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing MAXPOSITIONS"); + if (!commandArgs.Has("INITIALCASH")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing INITIALCASH"); + if (!commandArgs.Has("HOLDINGPERIOD")) MDTrace.WriteLine(LogLevel.DEBUG, "Missing HOLDINGPERIOD"); + return; + } + mgParams.MaxPositions=commandArgs.Coalesce("MAXPOSITIONS"); + mgParams.InitialCash=commandArgs.Coalesce("INITIALCASH"); + mgParams.HoldingPeriod=commandArgs.Coalesce("HOLDINGPERIOD"); + + if(commandArgs.Has("INCLUDETRADEMASTERFORSYMBOLSHELD")) + { + mgParams.IncludeTradeMasterForSymbolsHeld=commandArgs.Get("INCLUDETRADEMASTERFORSYMBOLSHELD"); + } + + if(commandArgs.Has("USESTOCHASTICS")) + { + mgParams.UseStochastics=commandArgs.Coalesce("USESTOCHASTICS",true); + } + + if(commandArgs.Has("USESTOPLIMITS")) + { + mgParams.UseStopLimits=commandArgs.Coalesce("USESTOPLIMITS",false); + } + + if(commandArgs.Has("STOPLIMITRISKPERCENTDECIMAL")) + { + mgParams.StopLimitRiskPercentDecimal=commandArgs.Coalesce("STOPLIMITRISKPERCENTDECIMAL",.12); + } + + if(commandArgs.Has("USEHEDGING")) + { + mgParams.UseHedging=commandArgs.Coalesce("USEHEDGING",false); + if(commandArgs.Has("INITIALHEDGECASH")) + { + mgParams.HedgeInitialCash=commandArgs.Get("INITIALHEDGECASH"); + } + } + + if(commandArgs.Has("KEEPSLOTPOSITIONS")) + { + mgParams.KeepSlotPositions=commandArgs.Get("KEEPSLOTPOSITIONS"); + } + +// ** M A C D + if(commandArgs.Has("USEMACD")) + { + mgParams.UseMACD=commandArgs.Coalesce("USEMACD",true); + } + if(commandArgs.Has("MACDREJECTSTRONGSELLSIGNALS")) + { + mgParams.MACDRejectStrongSellSignals=commandArgs.Coalesce("MACDREJECTSTRONGSELLSIGNALS",true); + } + if(commandArgs.Has("MACDREJECTWEAKSELLSIGNALS")) + { + mgParams.MACDRejectWeakSellSignals=commandArgs.Coalesce("MACDREJECTWEAKSELLSIGNALS",true); + } + if(commandArgs.Has("MACDSIGNALDAYS")) + { + mgParams.MACDSignalDays=commandArgs.Coalesce("MACDSIGNALDAYS",mgParams.MACDSignalDays); + } + if(commandArgs.Has("MACDSETUP")) + { + mgParams.MACDSetup=commandArgs.Coalesce("MACDSETUP",mgParams.MACDSetup); + } +// ** + MGSHQualityIndicator qualityIndicator=new MGSHQualityIndicator(MGSHQualityIndicator.QualityType.IDIndicator); + if(commandArgs.Has("QUALITYINDICATORTYPE")) qualityIndicator.Quality=MGSHQualityIndicator.ToQuality(commandArgs.Coalesce("QUALITYINDICATORTYPE","IDINDICATOR")); + mgParams.QualityIndicatorType=qualityIndicator.ToString(); + + mgParams.UseLowSlopeBetaCheck=true; + if(commandArgs.Has("USELOWSLOPEBETACHECK")) mgParams.UseLowSlopeBetaCheck=commandArgs.Coalesce("USELOWSLOPEBETACHECK",true); + + DateTime startDate = commandArgs.Coalesce("STARTDATE"); + DateTime endDate=commandArgs.Coalesce("ENDDATE",new DateTime()); + + DateGenerator dateGenerator = new DateGenerator(); + if(!dateGenerator.IsMarketOpen(startDate)) + { + MDTrace.WriteLine(LogLevel.DEBUG,$"STARTDATE {startDate.ToShortDateString()} is not a trading date."); + return; + } + if(!dateGenerator.IsMarketOpen(endDate)) + { + MDTrace.WriteLine(LogLevel.DEBUG,$"ENDDATE {endDate.ToShortDateString()} is not a trading date."); + return; + } + + if(!commandArgs.Has("SESSIONFILE")) + { + MDTrace.WriteLine(LogLevel.DEBUG,$"SESSIONFILE is a required parameter."); + return; + } + + String pathSessionFile = commandArgs.Get("SESSIONFILE"); + pathSessionFile = pathSessionFile.Trim(); + + List results=new List(); + MGSHMomentumBacktest backtestMomentum=new MGSHMomentumBacktest(); + results.Add(backtestMomentum.PerformBacktest(startDate, endDate, pathSessionFile, mgParams)); + } + } +}