Sync up with changes from ARM64

This commit is contained in:
2025-05-01 14:08:33 -04:00
parent 148c236af2
commit c0384feb95
40 changed files with 494 additions and 365 deletions

View File

@@ -131,7 +131,6 @@ namespace MarketData.Generator.CMMomentum
double gainLossClosedPositions=0.00;
double exposure=0.00;
double marketValue=0.00;
// if(HolidayDA.IsMarketHoliday(currentDate)) continue;
ModelPerformanceItem performanceItem=new ModelPerformanceItem();
foreach(MarketData.Generator.CMMomentum.Position openPosition in openPositions)
{

View File

@@ -16,17 +16,26 @@ namespace MarketData.Generator.CMTrend
public CMTCandidateGenerator()
{
}
// *******************************************************************************************************************************************************************************
// ******************************************************************* G E N E R A T E C A N D I D A T E - M A R C M I N E R V I N I ****************************************
// *******************************************************************************************************************************************************************************
public static CMTCandidate GenerateCandidate(String symbol,DateTime tradeDate,CMTParams cmtParams,List<String> symbolsHeld=null)
public static CMTCandidate GenerateCandidate(
String symbol,
DateTime tradeDate,
CMTParams cmtParams,
FundamentalV2 fundamental,
CompanyProfile companyProfile,
List<DateTime> historicalDates,
TimeSeriesCollection epsTimeSeries,
TimeSeriesCollection profitMarginTimeSeries,
List<String> symbolsHeld=null)
{
CMTCandidate cmtCandidate=new CMTCandidate();
try
{
// Check MarketCap
Fundamental fundamental=FundamentalDA.GetFundamentalMaxDate(symbol,tradeDate);
if(null==fundamental)
{
cmtCandidate.Violation=true;
@@ -54,7 +63,6 @@ namespace MarketData.Generator.CMTrend
return cmtCandidate;
}
// Equity check
CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(symbol);
if(null==companyProfile)
{
cmtCandidate.Violation=true;
@@ -93,7 +101,7 @@ namespace MarketData.Generator.CMTrend
cmtCandidate.Reason=String.Format("Insufficient pricing history, {0} days required.",PRICING_DAYS);
return cmtCandidate;
}
// Current Price Check
// Current Price Check. The current price must be equal to the trade date
Price currentPrice=prices[0];
if(currentPrice.Date.Date!=tradeDate.Date)
{
@@ -205,10 +213,7 @@ namespace MarketData.Generator.CMTrend
// generate a 14 day standard RSI with 30 days of pricing data
Prices rsiPrices=GBPriceCache.GetInstance().GetPrices(symbol,currentPrice.Date,30);
RSICollection rsiCollection=RSIGenerator.GenerateRSI(rsiPrices);
double rsi=rsiCollection[rsiCollection.Count-1].RSI;
// RSICollection rsiCollection=RSIGenerator.GenerateRSI(symbol,currentPrice.Date,30);
// double rsi=rsiCollection[rsiCollection.Count-1].RSI;
double rsi=rsiCollection[rsiCollection.Count-1].RSI;
if(null==rsiCollection||0==rsiCollection.Count||rsi<cmtParams.MinRSI)
{
cmtCandidate.Violation=true;
@@ -220,8 +225,6 @@ namespace MarketData.Generator.CMTrend
// Trend #3 check : check required days of increasing 200 day moving averages
DateGenerator dateGenerator=new DateGenerator();
List<double> dma200List=new List<double>();
DateTime historicalDate=dateGenerator.GenerateHistoricalDate(currentPrice.Date,cmtParams.DMA200Horizon+10);
List<DateTime> historicalDates=PricingDA.GetPricingDatesBetween(historicalDate,currentPrice.Date);
historicalDates=historicalDates.Take(cmtParams.DMA200Horizon).ToList();
if(historicalDates.Count<cmtParams.DMA200Horizon)
{
@@ -324,7 +327,6 @@ namespace MarketData.Generator.CMTrend
double epsSlope=double.NaN;
if(companyProfile.IsEquity&&cmtParams.EPSCheck)
{
TimeSeriesCollection epsTimeSeries=FundamentalDA.GetEPS(symbol,currentPrice.Date);
if(null==epsTimeSeries||epsTimeSeries.Count<3)
{
cmtCandidate.Violation=true;
@@ -350,7 +352,6 @@ namespace MarketData.Generator.CMTrend
// Trend#10 - My check - Increasing profit margin
if(companyProfile.IsEquity&&cmtParams.ProfitMarginCheck)
{
TimeSeriesCollection profitMarginTimeSeries=IncomeStatementDA.GetProfitMarginMaxAsOf(symbol,currentPrice.Date,IncomeStatement.PeriodType.Quarterly);
if(null==profitMarginTimeSeries||profitMarginTimeSeries.Count<3)
{
cmtCandidate.Violation=true;
@@ -362,7 +363,7 @@ namespace MarketData.Generator.CMTrend
minDate=profitMarginTimeSeries.Min(x => x.AsOf);
maxDate=profitMarginTimeSeries.Max(x => x.AsOf);
values=profitMarginTimeSeries.ToFloat();
values=Numerics.Reverse(ref values);
values=Numerics.Reverse(ref values); // because most recent date is in the lowest valued index bucket.
profitMarginSlope=Numerics.Slope(values);
if(profitMarginSlope<=0)
{

View File

@@ -1,4 +1,5 @@
using MarketData.DataAccess;
using Axiom.Interpreter;
using MarketData.DataAccess;
using MarketData.MarketDataModel;
using MarketData.Utils;
using System;
@@ -20,13 +21,58 @@ namespace MarketData.Generator.CMTrend
try
{
List<String> symbols=PricingDA.GetSymbols();
// Filter out symbols where we do not have a price on trade date
Profiler profiler = new Profiler();
Dictionary<String,DateTime> latestDates = PricingDA.GetLatestDates(symbols);
symbols=symbols.Where(x => latestDates.ContainsKey(x) && latestDates[x].Date>=tradeDate.Date).ToList();
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded pricing dates in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch a subset of fundamentals where each fundamental.asof is no greater than tradeDate
profiler.Reset();
FundamentalsV2 fundamentals = FundamentalDA.GetFundamentalsMaxDateV2(tradeDate);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded fundamentals in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch the Company Profiles
profiler.Reset();
Dictionary<String,CompanyProfile> companyProfiles = CompanyProfileDA.GetCompanyProfiles(symbols);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded company profiles in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch the pricing dates required for 200 day moving average.
profiler.Reset();
DateGenerator dateGenerator = new DateGenerator();
DateTime historicalDate=dateGenerator.GenerateHistoricalDate(tradeDate,cmtParams.DMA200Horizon+10);
List<DateTime> historicalDates=PricingDA.GetPricingDatesBetween(historicalDate,tradeDate);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded moving average dates in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch the EPS time series
profiler.Reset();
Dictionary<String,TimeSeriesCollection> epsTimeSeriesCollectionDictionary = FundamentalDA.GetEPS(symbols,tradeDate,3);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded EPS Time Series in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch the profit margin time series
profiler.Reset();
Dictionary<String,TimeSeriesCollection> profitMarginTimeSeriesCollectionDictionary = IncomeStatementDA.GetProfitMarginMaxAsOf(symbols,tradeDate,3,IncomeStatement.PeriodType.Quarterly);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded Profit Margin Time Series in {Utility.FormatNumber(profiler.End(),2)} (ms)");
for(int index=0;index<symbols.Count;index++)
{
String symbol=symbols[index];
if(0==(index%1000)) Console.WriteLine("Processing item {0} of {1}",index+1,symbols.Count);
CMTCandidate cmtCandidate=CMTCandidateGenerator.GenerateCandidate(symbol,tradeDate,cmtParams,symbolsHeld);
FundamentalV2 fundamental = default;
if(fundamentals.ContainsKey(symbol))fundamental=fundamentals[symbol];
CompanyProfile companyProfile = default;
if(companyProfiles.ContainsKey(symbol))companyProfile = companyProfiles[symbol];
TimeSeriesCollection epsTimeSeriesCollection = default;
if(epsTimeSeriesCollectionDictionary.ContainsKey(symbol))epsTimeSeriesCollection=epsTimeSeriesCollectionDictionary[symbol];
TimeSeriesCollection profitMarginTimeSeriesCollection = default;
if(profitMarginTimeSeriesCollectionDictionary.ContainsKey(symbol))profitMarginTimeSeriesCollection=profitMarginTimeSeriesCollectionDictionary[symbol];
CMTCandidate cmtCandidate=CMTCandidateGenerator.GenerateCandidate(symbol,tradeDate,cmtParams,fundamental,companyProfile,historicalDates,epsTimeSeriesCollection,profitMarginTimeSeriesCollection,symbolsHeld);
if(null==cmtCandidate) continue;
if(cmtCandidate.Violation) cmtGeneratorResult.CMTCandidatesWithViolation.Add(cmtCandidate);
else cmtGeneratorResult.CMTCandidates.Add(cmtCandidate);

View File

@@ -137,7 +137,6 @@ namespace MarketData.Generator.CMTrend
double gainLossClosedPositions=0.00;
double exposure=0.00;
double marketValue=0.00;
// if(HolidayDA.IsMarketHoliday(currentDate)) continue;
ModelPerformanceItem performanceItem=new ModelPerformanceItem();
foreach(MarketData.Generator.CMTrend.Position openPosition in openPositions)
{
@@ -799,11 +798,58 @@ namespace MarketData.Generator.CMTrend
List<CMTCandidate> violations=new List<CMTCandidate>();
List<CMTCandidate> candidates=new List<CMTCandidate>();
// Filter out symbols where we do not have a price on trade date
Profiler profiler = new Profiler();
Dictionary<String,DateTime> latestDates = PricingDA.GetLatestDates(symbols);
symbols=symbols.Where(x => latestDates.ContainsKey(x) && latestDates[x].Date>=analysisDate.Value.Date).ToList();
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded pricing dates in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch a subset of fundamentals where each fundamental.asof is no greater than tradeDate
profiler.Reset();
FundamentalsV2 fundamentals = FundamentalDA.GetFundamentalsMaxDateV2(analysisDate.Value);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded fundamentals in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch the company profiles
profiler.Reset();
Dictionary<String,CompanyProfile> companyProfiles = CompanyProfileDA.GetCompanyProfiles(symbols);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded company profiles in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch the pricing dates required for 200 day moving average.
profiler.Reset();
DateGenerator dateGenerator = new DateGenerator();
DateTime historicalDate=dateGenerator.GenerateHistoricalDate(analysisDate.Value,cmtParams.DMA200Horizon+10);
List<DateTime> historicalDates=PricingDA.GetPricingDatesBetween(historicalDate,analysisDate.Value);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded moving average dates in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch the EPS time series
profiler.Reset();
Dictionary<String,TimeSeriesCollection> epsTimeSeriesCollectionDictionary = FundamentalDA.GetEPS(symbols,analysisDate.Value,3);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded EPS Time Series in {Utility.FormatNumber(profiler.End(),2)} (ms)");
// Prefetch the profit margin time series
profiler.Reset();
Dictionary<String,TimeSeriesCollection> profitMarginTimeSeriesCollectionDictionary = IncomeStatementDA.GetProfitMarginMaxAsOf(symbols,analysisDate.Value,3,IncomeStatement.PeriodType.Quarterly);
MDTrace.WriteLine(LogLevel.DEBUG,$"Loaded Profit Margin Time Series in {Utility.FormatNumber(profiler.End(),2)} (ms)");
for(int index=0;index<symbols.Count;index++)
{
String symbol=symbols[index];
if(0==(index%500)) Console.WriteLine("GenerateCMTCandidates processing item {0} of {1}",index+1,symbols.Count);
CMTCandidate cmtCandidate=CMTCandidateGenerator.GenerateCandidate(symbol,analysisDate.Value,cmtParams);
FundamentalV2 fundamental = default;
if(fundamentals.ContainsKey(symbol))fundamental=fundamentals[symbol];
CompanyProfile companyProfile = default;
if(companyProfiles.ContainsKey(symbol))companyProfile = companyProfiles[symbol];
TimeSeriesCollection epsTimeSeriesCollection = default;
if(epsTimeSeriesCollectionDictionary.ContainsKey(symbol))epsTimeSeriesCollection=epsTimeSeriesCollectionDictionary[symbol];
TimeSeriesCollection profitMarginTimeSeriesCollection = default;
if(profitMarginTimeSeriesCollectionDictionary.ContainsKey(symbol))profitMarginTimeSeriesCollection=profitMarginTimeSeriesCollectionDictionary[symbol];
CMTCandidate cmtCandidate=CMTCandidateGenerator.GenerateCandidate(symbol,analysisDate.Value,cmtParams,fundamental,companyProfile,historicalDates,epsTimeSeriesCollection,profitMarginTimeSeriesCollection);
if(cmtCandidate.Violation) violations.Add(cmtCandidate);
else candidates.Add(cmtCandidate);
}

View File

@@ -121,7 +121,6 @@ namespace MarketData.Generator.Momentum
double gainLossClosedPositions=0.00;
double exposure=0.00;
double marketValue=0.00;
// if(HolidayDA.IsMarketHoliday(currentDate)) continue;
ModelPerformanceItem performanceItem=new ModelPerformanceItem();
foreach(MarketData.Generator.Momentum.Position openPosition in openPositions)
{
@@ -193,7 +192,8 @@ namespace MarketData.Generator.Momentum
AllPositions.DisplayTopFive();
MDTrace.WriteLine(LogLevel.DEBUG, "************** T O P L O S S E R S *************");
AllPositions.DisplayBottomFive();
DisplayBalanceFromPositions();
// DisplayBalanceFromPositions();
DisplayLatestModelPerformance(paramPathSessionFileName);
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("StartDate:{0}",Utility.DateTimeToStringMMHDDHYYYY(StartDate)));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("TradeDate:{0}",Utility.DateTimeToStringMMHDDHYYYY(TradeDate)));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("AnalysisDate:{0}",Utility.DateTimeToStringMMHDDHYYYY(AnalysisDate)));
@@ -591,6 +591,26 @@ namespace MarketData.Generator.Momentum
// *********************************************************************************************************************************************************************
// ************************************************************ E N D B U Y P O S I T I O N S ***********************************************
// *********************************************************************************************************************************************************************
private void DisplayLatestModelPerformance(String pathSessionFileName)
{
ModelPerformanceSeries performanceSeries=GetModelPerformance(pathSessionFileName);
if(null==performanceSeries || 0==performanceSeries.Count)return;
MDTrace.WriteLine("Date,Exposure,MarketValue,GainLossDoD,GainLoss,CumulativeGainLoss,R,(1+R),CumProd,CumProd-1,ClosedPositions");
ModelPerformanceItem modelPerformanceItem = performanceSeries[performanceSeries.Count-1]; // get the last record
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("\"{0}\",\"{1}\",\"{2}\",\"{3}\",\"{4}\",\"{5}\",\"{6}\",\"{7}\",\"{8}\",\"{9}\",\"{10}\"",
modelPerformanceItem.Date.ToShortDateString(),
Utility.FormatCurrency(modelPerformanceItem.Exposure),
Utility.FormatCurrency(modelPerformanceItem.MarketValue),
Utility.FormatCurrency(modelPerformanceItem.GainLossDOD),
Utility.FormatCurrency(modelPerformanceItem.GainLoss),
Utility.FormatCurrency(modelPerformanceItem.CumulativeGainLoss),
Utility.FormatNumber(modelPerformanceItem.R,4),
Utility.FormatNumber(modelPerformanceItem.OnePlusR,4),
Utility.FormatNumber(modelPerformanceItem.CumProd,4),
Utility.FormatNumber(modelPerformanceItem.CumProdMinusOne,4),
modelPerformanceItem.ClosedPositions));
}
private void DisplayBalance()
{
MDTrace.WriteLine(LogLevel.DEBUG,"*******************************************");

View File

@@ -1,16 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.Momentum
{
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;}}
}
}