Optimizations for CMTrend
This commit is contained in:
@@ -69,6 +69,54 @@ namespace MarketData.DataAccess
|
||||
}
|
||||
}
|
||||
|
||||
public static Dictionary<String,CompanyProfile> GetCompanyProfiles(List<String> symbols)
|
||||
{
|
||||
Dictionary<String,CompanyProfile> companyProfiles=new Dictionary<String,CompanyProfile>();
|
||||
MySqlConnection sqlConnection = null;
|
||||
MySqlDataReader sqlDataReader = null;
|
||||
MySqlCommand sqlCommand=null;
|
||||
String strQuery = null;
|
||||
|
||||
try
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
|
||||
sb.Append("select sm.symbol,sm.sector,sm.industry,sm.security_type,sm.company,cp.description,cp.pricing_source,cp.can_roll_previous,cp.freeze_pricing from securitymaster sm left outer join companyprofile cp on sm.symbol=cp.symbol").Append(" ");
|
||||
sb.Append("where sm.symbol in ").Append(SqlUtils.CreateInClause(symbols));
|
||||
strQuery = sb.ToString();
|
||||
sqlCommand = new MySqlCommand(strQuery, sqlConnection);
|
||||
sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
|
||||
sqlDataReader = sqlCommand.ExecuteReader();
|
||||
while(sqlDataReader.Read())
|
||||
{
|
||||
CompanyProfile companyProfile = new CompanyProfile();
|
||||
companyProfile.Symbol=sqlDataReader.GetString(0);
|
||||
if (!sqlDataReader.IsDBNull(1)) companyProfile.Sector = sqlDataReader.GetString(1);
|
||||
if (!sqlDataReader.IsDBNull(2)) companyProfile.Industry = sqlDataReader.GetString(2);
|
||||
if (!sqlDataReader.IsDBNull(3)) companyProfile.SecurityType = sqlDataReader.GetString(3);
|
||||
if (!sqlDataReader.IsDBNull(4)) companyProfile.CompanyName = sqlDataReader.GetString(4);
|
||||
if (!sqlDataReader.IsDBNull(5)) companyProfile.Description = sqlDataReader.GetString(5);
|
||||
if (!sqlDataReader.IsDBNull(6)) companyProfile.PricingSource = sqlDataReader.GetString(6).ToUpper();
|
||||
if (!sqlDataReader.IsDBNull(7)) companyProfile.CanRollPrevious = sqlDataReader.GetBoolean(7);
|
||||
if (!sqlDataReader.IsDBNull(8)) companyProfile.FreezePricing = sqlDataReader.GetBoolean(8);
|
||||
if(!companyProfiles.ContainsKey(companyProfile.Symbol))companyProfiles.Add(companyProfile.Symbol, companyProfile);
|
||||
}
|
||||
return companyProfiles;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,exception);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(null!=sqlCommand)sqlCommand.Dispose();
|
||||
if (null != sqlDataReader) {sqlDataReader.Close();sqlDataReader.Dispose();}
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static CompanyProfiles GetCompanyProfiles()
|
||||
{
|
||||
CompanyProfiles companyProfiles=new CompanyProfiles();
|
||||
|
||||
@@ -167,20 +167,31 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
public static TimeSeriesCollection GetEPS(String symbol,DateTime? maxDate=null)
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a collection of timeseries for the given symbols with each symbol having the specified max asof and no more than maxSeries elements in the series
|
||||
/// </summary>
|
||||
/// <param name="symbols"></param>
|
||||
/// <param name="maxDate"></param>
|
||||
/// <param name="maxSeries"></param>
|
||||
/// <returns></returns>
|
||||
public static Dictionary<String,TimeSeriesCollection> GetEPS(List<String> symbols, DateTime maxDate,int maxSeries)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
MySqlDataReader sqlDataReader = null;
|
||||
MySqlCommand sqlCommand = null;
|
||||
TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection();
|
||||
Dictionary<String,TimeSeriesCollection> timeSeriesCollection = new Dictionary<String,TimeSeriesCollection>();
|
||||
String strQuery = null;
|
||||
|
||||
try
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
|
||||
if(null==maxDate)sb.Append("select symbol,asof,eps from fundamentals where symbol='").Append(symbol).Append("' order by asof desc");
|
||||
else sb.Append("select symbol,asof,eps from fundamentals where symbol='").Append(symbol).Append("'").Append(" and asof<=").Append(SqlUtils.AddQuotes(SqlUtils.ToSqlDateTime(maxDate.Value))).Append(" order by asof desc");
|
||||
|
||||
sb.Append("SELECT B.symbol, B.asof, B.eps FROM ");
|
||||
sb.Append("(SELECT symbol, asof, eps, ROW_NUMBER() OVER(PARTITION BY symbol ORDER BY asof desc) AS rownum FROM fundamentals ");
|
||||
sb.Append($"WHERE symbol IN {SqlUtils.CreateInClause(symbols)} AND asof<={SqlUtils.ToSqlDate(maxDate,true)} )B ");
|
||||
sb.Append($"WHERE B.rownum<={maxSeries}");
|
||||
strQuery = sb.ToString(); ;
|
||||
sqlCommand = new MySqlCommand(strQuery, sqlConnection);
|
||||
sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
|
||||
@@ -195,7 +206,11 @@ namespace MarketData.DataAccess
|
||||
timeSeriesElement.Type = TimeSeriesElement.ElementType.OTHER;
|
||||
timeSeriesElement.OtherType = "EPS";
|
||||
if (double.IsNaN(timeSeriesElement.Value)) continue;
|
||||
timeSeriesCollection.Add(timeSeriesElement);
|
||||
if(!timeSeriesCollection.ContainsKey(timeSeriesElement.Symbol))
|
||||
{
|
||||
timeSeriesCollection.Add(timeSeriesElement.Symbol,new TimeSeriesCollection());
|
||||
}
|
||||
timeSeriesCollection[timeSeriesElement.Symbol].Add(timeSeriesElement);
|
||||
}
|
||||
return timeSeriesCollection;
|
||||
}
|
||||
@@ -210,7 +225,8 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlDataReader) {sqlDataReader.Close();sqlDataReader.Dispose();}
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Fundamental GetFundamental(String symbol)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
@@ -384,6 +400,65 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve latest MarketCap, PE, EBITDA, RevenuePerShare for all symbols with aasof being no more recent than the provided date
|
||||
/// Given a tradeDate of 04/18/2025 this method might return a collection similar to below. The model returned is a subset of the fundamental
|
||||
/// 07/15/2018 ^FTSE
|
||||
/// 03/13/2019 ^GSPC
|
||||
/// 04/17/2025 AA
|
||||
/// </summary>
|
||||
/// <param name="tradeDate">The as of date</param>
|
||||
/// <returns></returns>
|
||||
public static FundamentalsV2 GetFundamentalsMaxDateV2(DateTime tradeDate)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
MySqlDataReader sqlDataReader = null;
|
||||
MySqlCommand sqlCommand=null;
|
||||
String strQuery = null;
|
||||
FundamentalsV2 fundamentals = new FundamentalsV2();
|
||||
|
||||
try
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
|
||||
sb.Append("SELECT A.asof,A.symbol, A.market_cap,A.ebitda,A.pe,A.revenue_per_share FROM fundamentals A JOIN ");
|
||||
sb.Append("(SELECT MAX(asof) asof,symbol FROM fundamentals WHERE asof<=").Append("'");
|
||||
sb.Append(Utility.DateTimeToStringYYYYHMMHDD(tradeDate.Date));
|
||||
sb.Append("'");
|
||||
sb.Append(" GROUP BY symbol ORDER BY symbol ASC)B ");
|
||||
sb.Append(" ON A.asof=B.asof AND A.symbol=B.symbol ");
|
||||
strQuery = sb.ToString(); ;
|
||||
sqlCommand = new MySqlCommand(strQuery, sqlConnection);
|
||||
sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
|
||||
sqlDataReader = sqlCommand.ExecuteReader();
|
||||
while(sqlDataReader.Read())
|
||||
{
|
||||
FundamentalV2 fundamental = new FundamentalV2();
|
||||
fundamental.AsOf = sqlDataReader.GetDateTime(0);
|
||||
fundamental.Symbol = sqlDataReader.GetString(1);
|
||||
if(!sqlDataReader.IsDBNull(2)) fundamental.MarketCap = sqlDataReader.GetDouble(2);
|
||||
if(!sqlDataReader.IsDBNull(3)) fundamental.EBITDA = sqlDataReader.GetDouble(3);
|
||||
if(!sqlDataReader.IsDBNull(4)) fundamental.PE = sqlDataReader.GetDouble(4);
|
||||
if(!sqlDataReader.IsDBNull(5)) fundamental.RevenuePerShare = sqlDataReader.GetDouble(5);
|
||||
if(!fundamentals.ContainsKey(fundamental.Symbol))fundamentals.Add(fundamental.Symbol,fundamental);
|
||||
}
|
||||
return fundamentals;
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG,exception);
|
||||
return null;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if(null!=sqlCommand)sqlCommand.Dispose();
|
||||
if (null != sqlDataReader) {sqlDataReader.Close();sqlDataReader.Dispose();}
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static Fundamental GetFundamentalMaxDate(String symbol, DateTime asof)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static List<DateTime> GetIncomeStatementDates(String symbol,IncomeStatement.PeriodType periodType)
|
||||
{
|
||||
List<DateTime> incomeStatementDates = new List<DateTime>();
|
||||
@@ -82,6 +83,7 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static DateTime? GetLatestIncomeStatementDate(String symbol,IncomeStatement.PeriodType periodType)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
@@ -120,6 +122,7 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static IncomeStatement GetIncomeStatement(String symbol,IncomeStatement.PeriodType periodType)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
@@ -172,6 +175,7 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static TimeSeriesCollection GetRevenue(String symbol,IncomeStatement.PeriodType period)
|
||||
{
|
||||
Profiler profiler = new Profiler();
|
||||
@@ -215,6 +219,7 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
// Profit Margin is calculated as a percentage.
|
||||
public static TimeSeriesCollection GetProfitMargin(String symbol,IncomeStatement.PeriodType period=IncomeStatement.PeriodType.Annual)
|
||||
{
|
||||
@@ -263,10 +268,10 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
// Profit Margin is calculated as a percentage.
|
||||
public static TimeSeriesCollection GetProfitMarginMaxAsOf(String symbol,DateTime maxDate, IncomeStatement.PeriodType period = IncomeStatement.PeriodType.Annual)
|
||||
|
||||
public static Dictionary<String,TimeSeriesCollection> GetProfitMarginMaxAsOf(List<String> symbols, DateTime maxDate,int maxSeries,IncomeStatement.PeriodType period = IncomeStatement.PeriodType.Annual)
|
||||
{
|
||||
TimeSeriesCollection timeSeriesCollection = new TimeSeriesCollection();
|
||||
Dictionary<String,TimeSeriesCollection> timeSeriesCollection = new Dictionary<String,TimeSeriesCollection>();
|
||||
MySqlConnection sqlConnection = null;
|
||||
MySqlDataReader sqlDataReader = null;
|
||||
MySqlCommand sqlCommand = null;
|
||||
@@ -276,9 +281,11 @@ namespace MarketData.DataAccess
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("market_data"));
|
||||
sb.Append("select symbol,asof,total_revenue,gross_profit from incomestatement where symbol='").Append(symbol).Append("'").Append(" ");
|
||||
sb.Append(" and asof<='").Append(SqlUtils.SqlDate(maxDate)).Append("' ");
|
||||
sb.Append(" and period=").Append(period.Equals(IncomeStatement.PeriodType.Annual) ? 0 : 1).Append(" order by asof desc;");
|
||||
sb.Append("SELECT B.symbol, B.asof, B.total_revenue, B.gross_profit FROM ");
|
||||
sb.Append("(SELECT symbol, asof, total_revenue, gross_profit, period , ROW_NUMBER() OVER(PARTITION BY symbol ORDER BY asof desc) AS rownum FROM incomestatement ");
|
||||
sb.Append($" WHERE symbol IN {SqlUtils.CreateInClause(symbols)} AND asof<={SqlUtils.ToSqlDate(maxDate.Date,true)}");
|
||||
sb.Append($" AND period={(period.Equals(IncomeStatement.PeriodType.Annual) ? 0 : 1)} )B ");
|
||||
sb.Append($" WHERE B.rownum<={maxSeries} ");
|
||||
strQuery = sb.ToString();
|
||||
sqlCommand = new MySqlCommand(strQuery, sqlConnection);
|
||||
sqlCommand.CommandTimeout = SqlUtils.COMMAND_TIMEOUT;
|
||||
@@ -288,15 +295,19 @@ namespace MarketData.DataAccess
|
||||
TimeSeriesElement timeSeriesElement = new TimeSeriesElement();
|
||||
timeSeriesElement.Symbol = sqlDataReader.GetString(0);
|
||||
timeSeriesElement.AsOf = sqlDataReader.GetDateTime(1);
|
||||
timeSeriesElement.Type = period.Equals(IncomeStatement.PeriodType.Quarterly) ? TimeSeriesElement.ElementType.QuarterlyRevenue : TimeSeriesElement.ElementType.Revenue;
|
||||
|
||||
timeSeriesElement.Type = TimeSeriesElement.ElementType.OTHER;
|
||||
timeSeriesElement.OtherType = "Profit Margin %";
|
||||
if (sqlDataReader.IsDBNull(2)) continue;
|
||||
double total_revenue = sqlDataReader.GetDouble(2);
|
||||
if (sqlDataReader.IsDBNull(3)) continue;
|
||||
double gross_profit = sqlDataReader.GetDouble(3);
|
||||
if (0 == gross_profit) continue;
|
||||
timeSeriesElement.Value = (gross_profit / total_revenue) * 100.00;
|
||||
timeSeriesCollection.Add(timeSeriesElement);
|
||||
if(!timeSeriesCollection.ContainsKey(timeSeriesElement.Symbol))
|
||||
{
|
||||
timeSeriesCollection.Add(timeSeriesElement.Symbol, new TimeSeriesCollection());
|
||||
}
|
||||
timeSeriesCollection[timeSeriesElement.Symbol].Add(timeSeriesElement);
|
||||
}
|
||||
return timeSeriesCollection;
|
||||
}
|
||||
@@ -311,7 +322,8 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlDataReader) {sqlDataReader.Close();sqlDataReader.Dispose();}
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static IncomeStatement GetIncomeStatement(String symbol,DateTime asof,IncomeStatement.PeriodType periodType)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
@@ -362,6 +374,7 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static IncomeStatement GetIncomeStatementMaxAsOf(String symbol,DateTime asof,IncomeStatement.PeriodType periodType)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
@@ -413,6 +426,7 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool InsertIncomeStatements(List<IncomeStatement> incomeStatements)
|
||||
{
|
||||
MySqlConnection sqlConnection = null;
|
||||
@@ -479,6 +493,7 @@ namespace MarketData.DataAccess
|
||||
if (null != sqlConnection) sqlConnection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool DeleteIncomeStatements(List<IncomeStatement> incomeStatements, MySqlConnection sqlConnection, MySqlTransaction sqlTransaction)
|
||||
{
|
||||
for (int index = 0; index < incomeStatements.Count; index++)
|
||||
@@ -487,6 +502,7 @@ namespace MarketData.DataAccess
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool DeleteIncomeStatement(IncomeStatement incomeStatement, MySqlConnection sqlConnection, MySqlTransaction sqlTransaction)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -21,13 +21,46 @@ namespace MarketData.Generator.CMTrend
|
||||
try
|
||||
{
|
||||
List<String> symbols=PricingDA.GetSymbols();
|
||||
|
||||
// Filter out symbols where we do not have a price on trade date
|
||||
Dictionary<String,DateTime> latestDates = PricingDA.GetLatestDates(symbols);
|
||||
symbols=symbols.Where(x => latestDates.ContainsKey(x) && latestDates[x].Date>=tradeDate.Date).ToList();
|
||||
|
||||
// Prefetch a subset of fundamentals where each fundamental.asof is no greater than tradeDate
|
||||
FundamentalsV2 fundamentals = FundamentalDA.GetFundamentalsMaxDateV2(tradeDate);
|
||||
|
||||
// Prefetch the Company Profiles
|
||||
Dictionary<String,CompanyProfile> companyProfiles = CompanyProfileDA.GetCompanyProfiles(symbols);
|
||||
|
||||
// Prefetch the pricing dates requires for 200 day moving average.
|
||||
DateGenerator dateGenerator = new DateGenerator();
|
||||
DateTime historicalDate=dateGenerator.GenerateHistoricalDate(tradeDate,cmtParams.DMA200Horizon+10);
|
||||
List<DateTime> historicalDates=PricingDA.GetPricingDatesBetween(historicalDate,tradeDate);
|
||||
|
||||
// Prefetch the EPS time series
|
||||
Dictionary<String,TimeSeriesCollection> epsTimeSeriesCollectionDictionary = FundamentalDA.GetEPS(symbols,tradeDate,3);
|
||||
|
||||
// Prefetch the profit margin time series
|
||||
Dictionary<String,TimeSeriesCollection> profitMarginTimeSeriesCollectionDictionary = IncomeStatementDA.GetProfitMarginMaxAsOf(symbols,tradeDate,3,IncomeStatement.PeriodType.Quarterly);
|
||||
|
||||
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);
|
||||
|
||||
@@ -799,11 +799,45 @@ 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
|
||||
Dictionary<String,DateTime> latestDates = PricingDA.GetLatestDates(symbols);
|
||||
symbols=symbols.Where(x => latestDates.ContainsKey(x) && latestDates[x].Date>=analysisDate.Value.Date).ToList();
|
||||
|
||||
// Prefetch a subset of fundamentals where each fundamental.asof is no greater than tradeDate
|
||||
FundamentalsV2 fundamentals = FundamentalDA.GetFundamentalsMaxDateV2(analysisDate.Value);
|
||||
|
||||
// Prefetch the company profiles
|
||||
Dictionary<String,CompanyProfile> companyProfiles = CompanyProfileDA.GetCompanyProfiles(symbols);
|
||||
|
||||
// Prefetch the pricing dates requires for 200 day moving average.
|
||||
DateGenerator dateGenerator = new DateGenerator();
|
||||
DateTime historicalDate=dateGenerator.GenerateHistoricalDate(analysisDate.Value,cmtParams.DMA200Horizon+10);
|
||||
List<DateTime> historicalDates=PricingDA.GetPricingDatesBetween(historicalDate,analysisDate.Value);
|
||||
|
||||
// Prefetch the EPS time series
|
||||
Dictionary<String,TimeSeriesCollection> epsTimeSeriesCollectionDictionary = FundamentalDA.GetEPS(symbols,analysisDate.Value,3);
|
||||
|
||||
// Prefetch the profit margin time series
|
||||
Dictionary<String,TimeSeriesCollection> profitMarginTimeSeriesCollectionDictionary = IncomeStatementDA.GetProfitMarginMaxAsOf(symbols,analysisDate.Value,3,IncomeStatement.PeriodType.Quarterly);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
58
MarketData/MarketDataLib/MarketDataModel/FundamentalV2.cs
Normal file
58
MarketData/MarketDataLib/MarketDataModel/FundamentalV2.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Text;
|
||||
using MarketData.Utils;
|
||||
|
||||
namespace MarketData.MarketDataModel
|
||||
{
|
||||
public class FundamentalsV2 : Dictionary<String,FundamentalV2>
|
||||
{
|
||||
public FundamentalsV2()
|
||||
{
|
||||
}
|
||||
}
|
||||
public class FundamentalV2
|
||||
{
|
||||
private String symbol;
|
||||
private DateTime asOf;
|
||||
private double marketCap;
|
||||
private double pe;
|
||||
private double ebitda;
|
||||
private double revenuePerShare;
|
||||
|
||||
public FundamentalV2()
|
||||
{
|
||||
}
|
||||
public String Symbol
|
||||
{
|
||||
get { return symbol; }
|
||||
set { symbol = value; }
|
||||
}
|
||||
public DateTime AsOf
|
||||
{
|
||||
get { return asOf; }
|
||||
set { asOf = value; }
|
||||
}
|
||||
public double MarketCap
|
||||
{
|
||||
get { return marketCap; }
|
||||
set { marketCap = value; }
|
||||
}
|
||||
public double PE
|
||||
{
|
||||
get { return pe; }
|
||||
set { pe = value; }
|
||||
}
|
||||
public double RevenuePerShare
|
||||
{
|
||||
get { return revenuePerShare; }
|
||||
set { revenuePerShare = value; }
|
||||
}
|
||||
public double EBITDA
|
||||
{
|
||||
get { return ebitda; }
|
||||
set { ebitda = value; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,6 +220,10 @@ namespace MarketData.Utils
|
||||
if (Utility.IsEpoch(dateTime)) return null;
|
||||
return addQuotes?AddQuotes(Utility.DateTimeToStringYYYYHMMHDD(dateTime)):Utility.DateTimeToStringYYYYHMMHDD(dateTime);
|
||||
}
|
||||
public static String ToSqlDate(DateTime dateTime, bool addQuotes=false)
|
||||
{
|
||||
return SqlDate(dateTime, addQuotes);
|
||||
}
|
||||
public static String ToSqlDateTime(DateTime dateTime, bool addQuotes=false)
|
||||
{
|
||||
return addQuotes?AddQuotes(Utility.DateTimeToStringYYYYHMMHDDHHMMSS(dateTime)):Utility.DateTimeToStringYYYYHMMHDDHHMMSS(dateTime);
|
||||
|
||||
@@ -12,10 +12,9 @@ git push origin --delete <branch_name>
|
||||
git branch -r
|
||||
git branch -l
|
||||
|
||||
Please use the Microsoft.AspNet.WebApi.OwinSelfHost package for new projects.
|
||||
Microsoft.AspNet.WebApi.OwinSelfHost
|
||||
You can use the following commands to update the list of local branches from remote:
|
||||
git fetch --prune
|
||||
|
||||
dotnet add package Microsoft.AspNet.WebApi.OwinSelfHost
|
||||
|
||||
3) IPMonitor
|
||||
4) Models
|
||||
|
||||
Reference in New Issue
Block a user