using MarketData.CNNProcessing; using MarketData.DataAccess; using MarketData.Generator.MovingAverage; using MarketData.MarketDataModel; using MarketData.Utils; namespace MarketData.Generator.CMMomentum { public class CMMomentumGenerator { private CMMomentumGenerator() { } public static CMGeneratorResult GenerateCMCandidates(DateTime tradeDate,DateTime analysisDate,CMParams cmParams,List symbolsHeld) { CMGeneratorResult cmGeneratorResult = new CMGeneratorResult(); try { if(cmParams.UseCNN) { CNNClient cnnClient=new CNNClient(cmParams.UseCNNHost); if(!cnnClient.Ping()) { cmGeneratorResult.Success=false; cmGeneratorResult.Messages.Add(String.Format("The CNN server at {0} is not responding",cmParams.UseCNNHost)); return cmGeneratorResult; } } List symbols = PricingDA.GetSymbols(); bool checkBenchmarkSMAResult = CheckBenchmarkSMA(tradeDate,cmParams, cmGeneratorResult); if (!checkBenchmarkSMAResult && false == cmGeneratorResult.Success) return cmGeneratorResult; // indicates an error calulating the moving average if (false == checkBenchmarkSMAResult) { MDTrace.WriteLine(String.Format("The benchmark simple moving average is less than the benchmark price. Benchamrk:{0}, Days:{1}",cmParams.Benchmark,cmParams.BenchmarkMovingAverageDays)); cmGeneratorResult.CMCandidates = GenerateFallbackCandidates(tradeDate,analysisDate,cmParams,symbolsHeld); cmGeneratorResult.InFallback = true; return cmGeneratorResult; } for(int index=0;index> groups = cmGeneratorResult.CMCandidatesWithViolation.GroupBy(x => x.ReasonCategory).OrderByDescending(group => group.Count()).Select(group => Tuple.Create(group.Key, group.Count())); foreach(Tuple group in groups) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Group: {0} Count:{1}",group.Item1, group.Item2)); } MDTrace.WriteLine(LogLevel.DEBUG,String.Format($"Total Considered : {cmGeneratorResult.CMCandidates.Count+cmGeneratorResult.CMCandidatesWithViolation.Count}")); MDTrace.WriteLine(LogLevel.DEBUG,String.Format($"Total Disqualified : {cmGeneratorResult.CMCandidatesWithViolation.Count}")); MDTrace.WriteLine(LogLevel.DEBUG,String.Format($"Total Eligible : {cmGeneratorResult.CMCandidates.Count}")); MDTrace.WriteLine(LogLevel.DEBUG,"******************************************************************************************************"); } if (0 == cmGeneratorResult.CMCandidates.Count) { cmGeneratorResult.CMCandidates = GenerateFallbackCandidates(tradeDate, analysisDate, cmParams,symbolsHeld); cmGeneratorResult.InFallback = true; } if (null == cmGeneratorResult.CMCandidates || 0 == cmGeneratorResult.CMCandidates.Count) { MDTrace.WriteLine(String.Format("Unable to produce any candidates for TradeDate {0}", tradeDate)); return null; } cmGeneratorResult.CMCandidates = new CMCandidates((from CMCandidate cmCandidate in cmGeneratorResult.CMCandidates select cmCandidate).OrderByDescending(x => x.Score).ThenByDescending(x=>x.SharpeRatio).ToList().Take(cmParams.MaxPositions).ToList()); cmGeneratorResult.Success = true; return cmGeneratorResult; } catch (Exception exception) { cmGeneratorResult.Success = false; cmGeneratorResult.Messages.Add(exception.ToString()); MDTrace.WriteLine(LogLevel.DEBUG, exception.ToString()); return cmGeneratorResult; } } public static CMCandidates GenerateFallbackCandidates(DateTime tradeDate,DateTime analysisDate,CMParams cmParams,List symbolsHeld) { CMCandidates cmCandidates = new CMCandidates(); if (null == cmParams || null == cmParams.FallbackCandidateBestOf) return null; List fallbackCandidateSymbols = Utility.ToList(cmParams.FallbackCandidateBestOf); if (null != symbolsHeld && 0 != symbolsHeld.Count) fallbackCandidateSymbols = fallbackCandidateSymbols.Except(symbolsHeld).ToList(); foreach (String symbol in fallbackCandidateSymbols) { CMCandidate cmCandidate = CMCandidateGenerator.GenerateCandidateForFallback(symbol, tradeDate,analysisDate,cmParams,null); if (null == cmCandidate || cmCandidate.Violation) continue; cmCandidates.Add(cmCandidate); } cmCandidates = new CMCandidates((from CMCandidate cmCandidate in cmCandidates select cmCandidate).OrderByDescending(x => x.Score).ToList()); cmCandidates = new CMCandidates(cmCandidates.Take(1).ToList()); if (null == cmCandidates || 0 == cmCandidates.Count) // Guarantee that we get a candidate { CMCandidate cmCandidate = CMCandidateGenerator.GetFallbackCandidateOfLastResort(Utility.ToList(cmParams.FallbackCandidateBestOf), tradeDate, analysisDate, cmParams); cmCandidates.Add(cmCandidate); } return cmCandidates; } private static bool CheckBenchmarkSMA(DateTime tradeDate,CMParams cmParams, CMGeneratorResult cmGeneratorResult) { Prices pricesDMA = PricingDA.GetPrices(cmParams.Benchmark, tradeDate, cmParams.BenchmarkMovingAverageDays + 15); if (null == pricesDMA || (cmParams.BenchmarkMovingAverageDays + 15) != pricesDMA.Count) { cmGeneratorResult.Success = false; cmGeneratorResult.Messages.Add(String.Format("Insufficient pricing to generate {0} day moving average for {0}. Required {2} days.", cmParams.Benchmark, cmParams.BenchmarkMovingAverageDays, cmParams.BenchmarkMovingAverageDays + 15)); return false; } DMAPrices dmaPrices = MovingAverageGenerator.GenerateMovingAverage(pricesDMA, cmParams.BenchmarkMovingAverageDays); if (dmaPrices[0].CurrentPrice < dmaPrices[0].AVGPrice) { cmGeneratorResult.Success = true; cmGeneratorResult.Messages.Add(String.Format("Current price for {0} is less than moving average. {1}<{2} on {3}", cmParams.Benchmark, dmaPrices[0].CurrentPrice, dmaPrices[0].AVGPrice, dmaPrices[0].Date.ToShortDateString())); return false; } return true; } // This method is made public in order that it can be tested public static bool PredictCandidate(CMCandidate cmCandidate,CMParams cmParams) { try { CNNClient cnnClient=new CNNClient(cmParams.UseCNNHost); DataProcessor dataProcessor=new DataProcessor(); dataProcessor.Width=128; dataProcessor.Height=128; dataProcessor.PenWidth=1; TestCase testCase=new TestCase(cmCandidate.Symbol,cmCandidate.TradeDate,cmParams.UseCNNDayCount,TestCase.CaseType.Test,TestCase.GenerateType.BollingerBand,TestCase.OutputType.OutputStream); dataProcessor.ProcessData(testCase); String prediction = cnnClient.Predict(CNNClient.Model.resnet50_20241024_270,testCase.LastStream); prediction=prediction.Substring(prediction.IndexOf("-->")); int result=int.Parse(Utility.BetweenString(prediction,"[[","]")); if(1==result) { cmCandidate.Score*=(1.00+cmParams.UseCNNRewardPercentDecimal); // increase the score by the percentage indicated in the params settings cmCandidate.CNNPrediction=true; } return true; } catch(Exception exception) { MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Error encountered calling convolutional model at {0}. Exception was {1}",cmParams.UseCNNHost,exception.ToString())); return false; } } } }