Files
marketdata/MarketDataLib/Generator/CMMomentum/CMMomentumGenerator.cs

199 lines
10 KiB
C#

using MarketData.CNNProcessing;
using MarketData.DataAccess;
using MarketData.Generator.MovingAverage;
using MarketData.MarketDataModel;
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace MarketData.Generator.CMMomentum
{
public class CMMomentumGenerator
{
private CMMomentumGenerator()
{
}
public static CMGeneratorResult GenerateCMCandidates(DateTime tradeDate,DateTime analysisDate,CMParams cmParams,List<String> 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<String> 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<symbols.Count;index++)
{
String symbol = symbols[index];
if (0 == (index % 500)) MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Processing item {0} of {1}", index + 1, symbols.Count));
CMCandidate cmCandidate = CMCandidateGenerator.GenerateCandidate(symbol,tradeDate,analysisDate,cmParams,symbolsHeld);
if (null == cmCandidate) continue;
if (cmCandidate.Violation)
{
cmGeneratorResult.CMCandidatesWithViolation.Add(cmCandidate);
}
else
{
if(cmParams.UseCNN)PredictCandidate(cmCandidate,cmParams);
cmGeneratorResult.CMCandidates.Add(cmCandidate);
}
}
if(null!=cmGeneratorResult.CMCandidatesWithViolation && 0!=cmGeneratorResult.CMCandidatesWithViolation.Count)
{
MDTrace.WriteLine(LogLevel.DEBUG,"**************** C A N D I D A T E S U M M A R Y ************************");
IEnumerable<Tuple<string, int>> groups = cmGeneratorResult.CMCandidatesWithViolation.GroupBy(x => x.ReasonCategory).OrderByDescending(group => group.Count()).Select(group => Tuple.Create(group.Key, group.Count()));
foreach(Tuple<string, int> 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<String> symbolsHeld)
{
CMCandidates cmCandidates = new CMCandidates();
if (null == cmParams || null == cmParams.FallbackCandidateBestOf) return null;
List<String> 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;
// }
//}
// 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();
int imageDimensions=224;
dataProcessor.Width=imageDimensions;
dataProcessor.Height=imageDimensions;
dataProcessor.PenWidth=1;
TestCase testCase=new TestCase(cmCandidate.Symbol,cmCandidate.TradeDate,cmParams.UseCNNDayCount,TestCase.CaseType.Test,TestCase.GenerateType.BollingerBandWithVIX,TestCase.OutputType.OutputStream);
dataProcessor.ProcessData(testCase);
Stream streamResult = cnnClient.ProcessImage(testCase.LastStream); // process the image through PIL
String prediction = cnnClient.Predict(CNNClient.Model.convnext,streamResult);
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;
}
}
}
}