diff --git a/MarketData/MarketDataLib/DataAccess/WatchListDA.cs b/MarketData/MarketDataLib/DataAccess/WatchListDA.cs
index f98440a..25ed7d6 100755
--- a/MarketData/MarketDataLib/DataAccess/WatchListDA.cs
+++ b/MarketData/MarketDataLib/DataAccess/WatchListDA.cs
@@ -10,6 +10,29 @@ namespace MarketData.DataAccess
private WatchListDA()
{
}
+
+ ///
+ /// AddToWatchList - Add list of symbols to specified watch list
+ ///
+ ///
+ ///
+ ///
+ public static bool AddToWatchList(List symbols,String watchListName = "Valuations")
+ {
+ if(null == symbols || 0==symbols.Count || String.IsNullOrEmpty(watchListName))return false;
+ foreach(string symbol in symbols)
+ {
+ AddToWatchList(symbol, watchListName);
+ }
+ return true;
+ }
+
+ ///
+ /// AddToWatchList - This will ignore the insert if the record already exists
+ ///
+ ///
+ ///
+ ///
public static bool AddToWatchList(String symbol, String watchListName = "Valuations")
{
MySqlConnection sqlConnection = null;
@@ -23,11 +46,11 @@ namespace MarketData.DataAccess
symbol = symbol.ToUpper();
WatchListItem watchListItem = GetWatchListItem(watchListName);
if (null == watchListItem) return false;
- if (IsInWatchList(symbol, watchListName)) return true;
+// if (IsInWatchList(symbol, watchListName)) return true;
sqlConnection = SqlUtils.CreateMySqlConnection(MainDataSource.Instance.LocateDataSource("portfolio_data"));
sqlTransaction = sqlConnection.BeginTransaction(System.Data.IsolationLevel.ReadCommitted);
StringBuilder sb = new StringBuilder();
- sb.Append("insert into watchlist(watch_list_id,symbol)values(");
+ sb.Append("insert ignore into watchlist(watch_list_id,symbol)values(");
sb.Append(watchListItem.WatchListId).Append(",");
sb.Append(SqlUtils.AddQuotes(symbol));
sb.Append(")");
@@ -50,6 +73,7 @@ namespace MarketData.DataAccess
if (null != sqlConnection) sqlConnection.Close();
}
}
+
public static bool RemoveFromWatchList(String symbol, String watchListName = "Valuations")
{
MySqlConnection sqlConnection = null;
@@ -88,6 +112,7 @@ namespace MarketData.DataAccess
if (null != sqlConnection) sqlConnection.Close();
}
}
+
public static bool IsInWatchList(String symbol, String watchListName = "Valuations")
{
MySqlConnection sqlConnection = null;
@@ -123,6 +148,7 @@ namespace MarketData.DataAccess
if (null != sqlConnection) sqlConnection.Close();
}
}
+
public static List GetWatchList(String watchListName)
{
MySqlConnection sqlConnection = null;
@@ -160,6 +186,7 @@ namespace MarketData.DataAccess
if (null != sqlConnection) sqlConnection.Close();
}
}
+
public static WatchListItem GetWatchListItem(String watchListName)
{
MySqlConnection sqlConnection = null;
@@ -197,6 +224,7 @@ namespace MarketData.DataAccess
if (null != sqlConnection) sqlConnection.Close();
}
}
+
public static List GetWatchLists()
{
MySqlConnection sqlConnection = null;
diff --git a/MarketData/MarketDataLib/Generator/CMMomentum/CMBacktest.cs b/MarketData/MarketDataLib/Generator/CMMomentum/CMBacktest.cs
index 3e439bc..7a0d55b 100755
--- a/MarketData/MarketDataLib/Generator/CMMomentum/CMBacktest.cs
+++ b/MarketData/MarketDataLib/Generator/CMMomentum/CMBacktest.cs
@@ -143,8 +143,8 @@ namespace MarketData.Generator.CMMomentum
price=PricingDA.GetPrice(openPosition.Symbol,currentDate);
if(null==price)
{
- MDTrace.WriteLine(LogLevel.DEBUG,String.Format("No price for {0} on {1}",openPosition.Symbol,currentDate.ToShortDateString()));
- return null;
+ MDTrace.WriteLine(LogLevel.DEBUG,String.Format("******************* No price for {0} on {1} *****************",openPosition.Symbol,currentDate.ToShortDateString()));
+ continue; // Log a message and continue otherwise upstream fails entirely.
}
LocalPriceCache.GetInstance().Add(price);
}
@@ -399,6 +399,7 @@ namespace MarketData.Generator.CMMomentum
double cashAllocation = Math.Min(CashBalance, (ActivePositions.GetExposure() + CashBalance) / HoldingPeriod); // Even out the cash allocation so that no one slot eats up all the cash
Positions positions=BuyPositions(slotIndex,TradeDate,AnalysisDate,cashAllocation,SymbolsHeld());
DisplayPurchases(positions, TradeDate);
+ AddToWatchList(positions);
MDTrace.WriteLine(LogLevel.DEBUG,"********************** B U Y ********************");
positions.Display();
if (CashBalance - positions.Exposure <= 0.00)
@@ -475,6 +476,26 @@ namespace MarketData.Generator.CMMomentum
}
}
+ ///
+ /// AddToWatchList - Add purchased positions to watch list for price tracking
+ ///
+ ///
+ ///
+ private static void AddToWatchList(Positions positions)
+ {
+ try
+ {
+ if(null==positions || 0==positions.Count)return;
+ List symbols = positions.Select(x=>x.Symbol).ToList();
+ MDTrace.WriteLine(LogLevel.DEBUG,$"Adding {string.Join(",",symbols)} to WatchList");
+ WatchListDA.AddToWatchList(symbols);
+ }
+ catch(Exception exception)
+ {
+ MDTrace.WriteLine(LogLevel.DEBUG,$"{exception.ToString()}");
+ }
+ }
+
private void SellPositions(Positions positions, DateTime sellDate)
{
DateGenerator dateGenerator = new DateGenerator();
diff --git a/MarketData/MarketDataLib/Generator/CMTrend/CMTTrendModel.cs b/MarketData/MarketDataLib/Generator/CMTrend/CMTTrendModel.cs
index fbecd13..29966c4 100755
--- a/MarketData/MarketDataLib/Generator/CMTrend/CMTTrendModel.cs
+++ b/MarketData/MarketDataLib/Generator/CMTrend/CMTTrendModel.cs
@@ -150,7 +150,7 @@ namespace MarketData.Generator.CMTrend
if(null==price)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("******************* No price for {0} on {1} *****************",openPosition.Symbol,currentDate.ToShortDateString()));
- return performanceSeries;
+ continue; // Log a message and continue.
}
gainLoss+=((price.Close*openPosition.Shares)-(openPosition.PurchasePrice*openPosition.Shares));
marketValue+=(price.Close*openPosition.Shares);
@@ -653,6 +653,7 @@ namespace MarketData.Generator.CMTrend
}
ActivePositions.Add(positions);
DisplayPurchases(positions, TradeDate);
+ AddToWatchList(positions);
CashBalance-=positions.GetExposure();
}
DisplayRealtimeBlotter(TradeDate);
@@ -755,6 +756,7 @@ namespace MarketData.Generator.CMTrend
}
ActivePositions.Add(positions);
DisplayPurchases(positions, TradeDate);
+ AddToWatchList(positions);
CashBalance-=positions.GetExposure();
}
MDTrace.WriteLine(LogLevel.DEBUG,"\n");
@@ -1818,6 +1820,25 @@ namespace MarketData.Generator.CMTrend
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Buy {0} {1} @ {2} on {3}",position.Symbol,Utility.FormatNumber(position.Shares,3),Utility.FormatCurrency(position.PurchasePrice,2),tradeDate.ToShortDateString()));
}
- }
+ }
+ ///
+ /// AddToWatchList - Add purchased positions to watch list for price tracking
+ ///
+ ///
+ ///
+ private static void AddToWatchList(Positions positions)
+ {
+ try
+ {
+ if(null==positions || 0==positions.Count)return;
+ List symbols = positions.Select(x=>x.Symbol).ToList();
+ MDTrace.WriteLine(LogLevel.DEBUG,$"Adding {string.Join(",",symbols)} to WatchList");
+ WatchListDA.AddToWatchList(symbols);
+ }
+ catch(Exception exception)
+ {
+ MDTrace.WriteLine(LogLevel.DEBUG,$"{exception.ToString()}");
+ }
+ }
}
}
diff --git a/MarketData/MarketDataLib/Generator/MGSHMomentum/MGSHBacktest.cs b/MarketData/MarketDataLib/Generator/MGSHMomentum/MGSHBacktest.cs
index c38422b..5b270a1 100755
--- a/MarketData/MarketDataLib/Generator/MGSHMomentum/MGSHBacktest.cs
+++ b/MarketData/MarketDataLib/Generator/MGSHMomentum/MGSHBacktest.cs
@@ -508,6 +508,7 @@ namespace MarketData.Generator.MGSHMomentum
return;
}
DisplayPurchases(positions,TradeDate);
+ AddToWatchList(positions);
ActivePositions.Add(slotIndex,positions);
CashBalance-=positions.Exposure;
SetInitialStopLimitsForNewPositions(TradeDate, positions);
@@ -545,6 +546,7 @@ namespace MarketData.Generator.MGSHMomentum
if(!ActivePositions.ContainsKey(slotIndex))ActivePositions.Add(slotIndex, positions);
else ActivePositions[slotIndex].AddRange(positions);
DisplayPurchases(positions, TradeDate);
+ AddToWatchList(positions);
CashBalance-=positions.Exposure;
SetInitialStopLimitsForNewPositions(TradeDate, positions);
ActivePositions[slotIndex].Display();
@@ -1442,5 +1444,24 @@ namespace MarketData.Generator.MGSHMomentum
}
}
+ ///
+ /// AddToWatchList - Add purchased positions to watch list for price tracking
+ ///
+ ///
+ ///
+ private static void AddToWatchList(MGSHPositions positions)
+ {
+ try
+ {
+ if(null==positions || 0==positions.Count)return;
+ List symbols = positions.Select(x=>x.Symbol).ToList();
+ MDTrace.WriteLine(LogLevel.DEBUG,$"Adding {string.Join(",",symbols)} to WatchList");
+ WatchListDA.AddToWatchList(symbols);
+ }
+ catch(Exception exception)
+ {
+ MDTrace.WriteLine(LogLevel.DEBUG,$"{exception.ToString()}");
+ }
+ }
}
}
diff --git a/MarketData/MarketDataLib/Generator/Momentum/Backtest.cs b/MarketData/MarketDataLib/Generator/Momentum/Backtest.cs
index f2d3cd5..cd71406 100755
--- a/MarketData/MarketDataLib/Generator/Momentum/Backtest.cs
+++ b/MarketData/MarketDataLib/Generator/Momentum/Backtest.cs
@@ -369,6 +369,7 @@ namespace MarketData.Generator.Momentum
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("********** Insufficient funds to make additional purchases.**************"));
}
DisplayPurchases(positions,TradeDate);
+ AddToWatchList(positions);
positions.Display();
ActivePositions.Add(slotIndex,positions);
CashBalance-=positions.Exposure;
@@ -398,6 +399,7 @@ namespace MarketData.Generator.Momentum
break;
}
DisplayPurchases(positions, TradeDate);
+ AddToWatchList(positions);
ActivePositions[slotIndex]=positions;
CashBalance-=positions.Exposure;
DisplayBalance();
@@ -749,6 +751,26 @@ namespace MarketData.Generator.Momentum
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Buy {0} {1} @ {2} on {3}",position.Symbol,Utility.FormatNumber(position.Shares,3),Utility.FormatCurrency(position.PurchasePrice,2),tradeDate.ToShortDateString()));
}
- }
+ }
+
+ ///
+ /// AddToWatchList - Add purchased positions to watch list for price tracking
+ ///
+ ///
+ ///
+ private static void AddToWatchList(Positions positions)
+ {
+ try
+ {
+ if(null==positions || 0==positions.Count)return;
+ List symbols = positions.Select(x=>x.Symbol).ToList();
+ MDTrace.WriteLine(LogLevel.DEBUG,$"Adding {string.Join(",",symbols)} to WatchList");
+ WatchListDA.AddToWatchList(symbols);
+ }
+ catch(Exception exception)
+ {
+ MDTrace.WriteLine(LogLevel.DEBUG,$"{exception.ToString()}");
+ }
+ }
}
}
diff --git a/MarketData/MarketDataLib/Generator/Momentum/MomentumGenerator.cs b/MarketData/MarketDataLib/Generator/Momentum/MomentumGenerator.cs
index 17a2606..a608098 100755
--- a/MarketData/MarketDataLib/Generator/Momentum/MomentumGenerator.cs
+++ b/MarketData/MarketDataLib/Generator/Momentum/MomentumGenerator.cs
@@ -393,304 +393,5 @@ namespace MarketData.Generator.Momentum
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MomentumGenertor.GenerateMomentum:{0} candidates",momentumCandidates.Count()));
return momentumCandidates;
}
-
-/*
-// This interface is called by the Backtest
- public static MomentumCandidates GenerateMomentum(DateTime tradeDate,List symbolsHeld,MGConfiguration config)
- {
- DateGenerator dateGenerator=new DateGenerator();
- List symbols=PricingDA.GetSymbols();
- MomentumCandidates momentumCandidates=new MomentumCandidates();
- MomentumCandidates highPECandidates=new MomentumCandidates();
- DateTime startDateOfReturns=dateGenerator.GetPrevMonthEnd(tradeDate,2);
- List noTradeSymbols=Utility.ToList(config.NoTradeSymbols);
- List noTradeFinancialSymbols=Utility.ToList(config.NoTradeFinancialSymbols);
- CandidateViolations candidateViolations = new CandidateViolations();
-
- MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Generate momentum.. examining candidates"));
-// Go through the universe of stocks
- for(int index=0;indexx.Equals(symbol, StringComparison.CurrentCultureIgnoreCase)))
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate already held."));
- continue;
- }
-
-// Check if the symbol is in the no trade list (i.e.) Bitcoin etc.,
- if(noTradeSymbols.Any(x=>x.Equals(symbol, StringComparison.CurrentCultureIgnoreCase)))
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate in NoTradeSymbol."));
- continue;
- }
-
-// Check MarketCap, EBITDA, PE, and Revenue Per Share
- Fundamental fundamental=FundamentalDA.GetFundamentalMaxDate(symbol,tradeDate);
- if(null==fundamental)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate no fundamental."));
- continue;
- }
-
- if(!(fundamental.MarketCap>=config.MarketCapLowerLimit))
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate MarketCapLimit."));
- continue;
- }
-
- if(config.UseEBITDAScreen && (double.IsNaN(fundamental.EBITDA)||fundamental.EBITDA<=0))
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate EBITDA violation."));
- continue;
- }
-
- if(config.UseRevenuePerShareScreen && (double.IsNaN(fundamental.RevenuePerShare)||fundamental.RevenuePerShare<0.00))
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate RevenuePerShare violation."));
- continue;
- }
-
-// Initial PE screening. This screen checks for existance of PE and if it is availabe it must be >0.00 . There is another PE based on limits further below
- if(config.UsePEScreen && (double.IsNaN(fundamental.PE)||fundamental.PE<=0.00))
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate PE violation."));
- continue;
- }
-
-// Exclude any company in the "Financial" sector
- CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(symbol);
- if(null!=companyProfile&&null!=companyProfile.Sector&&noTradeFinancialSymbols.Any(x=>x.Equals(companyProfile.Sector)))
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate Financial Sector violation."));
- continue;
- }
-
-// Fetch single day price
- Price price=GBPriceCache.GetInstance().GetPrice(symbol,tradeDate);
- if(null==price)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate missing price on trade date."));
- continue;
- }
-// Filter penny stocks - don't trade anything less than $1.00
- if(price.Close<1.00||price.Open<1.00)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate penny stock violation."));
- continue;
- }
-
-// Retrieve prices
- Prices prices=null;
- prices=GBPriceCache.GetInstance().GetPrices(symbol,tradeDate,(int)MomentumGeneratorConstants.DayCount);
- if(null==prices||prices.Count!=(int)MomentumGeneratorConstants.DayCount)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate missing price history."));
- continue;
- }
-
-// calculate the one day return
- double return1D=prices.GetReturn1D();
-
-// Liquidity check - if any day has volume < 10,000 then we reject it
- if(((from Price xPrice in prices where xPrice.Volume<10000 select xPrice).Count())>1)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Liquidity violation."));
- continue;
- }
-
-// Calculate velocity as a percentage range of the open price within the 252+20 day range of prices - This is used for display purposes
- double velocity;
- Prices velocityPrices=GBPriceCache.GetInstance().GetPrices(symbol,tradeDate,(int)MomentumGenerator.MomentumGeneratorConstants.DayCount+20);
- double priceHigh=(from Price selectPrice in velocityPrices select selectPrice.Open).Max();
- double priceLow=(from Price selectPrice in velocityPrices select selectPrice.Open).Min();
- if(0.00==priceHigh-priceLow)velocity=0.00;
- else velocity=((price.Open-priceLow)*(100/(priceHigh-priceLow)))/100.00;
-
-// Price slopes - These are used for display purposes
- double[] pricesArray=null;
- LeastSquaresResult leastSquaresResult;
-
-// Get the benchmark pricing low pricing data and check the slope of previous lows; only if Beta of candidate is >= LowSlopeBetaThreshhold
-// The idea behind this check is that a high beta stock will track to the benchmark. So if the benchmark lows are forming a downward pattern then we
-// assume that this is a somewhat bearish condition. The config has the setting at a 15 day check and the threshold beta set to 1.00
- if(config.UseLowSlopeBetaCheck && fundamental.Beta>=config.LowSlopeBetaThreshhold)
- {
- Prices benchmarkPrices=GBPriceCache.GetInstance().GetPrices(config.Benchmark,tradeDate,config.LowSlopeBetaDays);
- pricesArray=Numerics.ToDouble(benchmarkPrices.GetPricesLow());
- leastSquaresResult=Numerics.LeastSquares(pricesArray);
- double slopeBmk=leastSquaresResult.Slope;
- if(slopeBmk<0)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Beta threshhold violation."));
- continue;
- }
- }
-
-// *** MACDSignal detection
- if(config.UseMACD)
- {
- MACDSetup macdSetup=new MACDSetup(config.MACDSetup);
- MACDSignals macdSignals=MACDGenerator.GenerateMACD(prices,macdSetup);
- Signals signalsMACD = SignalGenerator.GenerateSignals(macdSignals);
- signalsMACD=new Signals(signalsMACD.Take(config.MACDSignalDays).ToList());
- int weakSellSignals=(from Signal signal in signalsMACD where signal.IsWeakSell() select signal).Count();
- int strongSellSignals=(from Signal signal in signalsMACD where signal.IsStrongSell() select signal).Count();
- if(config.MACDRejectWeakSellSignals && weakSellSignals>0)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"MACD Reject Weak Sell violation."));
- continue;
- }
- if(config.MACDRejectStrongSellSignals && strongSellSignals>0)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"MACD Reject Strong Sell violation."));
- continue;
- }
- }
-
-// *** Stochastics oscillator
- if(config.UseStochastics)
- {
- Stochastics stochastics=StochasticsGenerator.GenerateStochastics(prices);
- Signals signalsStochastics=new Signals(SignalGenerator.GenerateSignals(stochastics).OrderByDescending(x => x.SignalDate).ToList());
- signalsStochastics=new Signals(signalsStochastics.Take(config.StochasticsSignalDays).ToList());
- int weakSellCount=(from Signal signal in signalsStochastics where signal.IsWeakSell() select signal).Count();
- int strongSellCount=(from Signal signal in signalsStochastics where signal.IsStrongSell() select signal).Count();
- if(config.StochasticsRejectStrongSells&&strongSellCount>0)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Stochastics Oscillator Reject Strong Sell violation."));
- continue;
- }
- if(config.StochasticsRejectWeakSells&&weakSellCount>0)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Stochastics Oscillator Reject Weak Sell violation."));
- continue;
- }
- }
-
-// Analyst Ratings - "Downgrades" that are more than a year old (252 days) are not considered. Mean reversion.... bad companies improve, good companies decline.
- DateTime minRatingDate=dateGenerator.GenerateHistoricalDate(startDateOfReturns,(int)MomentumGeneratorConstants.DayCount);
- AnalystRatings analystRatings=AnalystRatingsDA.GetAnalystRatingsMaxDateNoZacks(symbol,tradeDate);
- analystRatings.RemoveAll(x => x.Date.50 select value).Count()>0)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate pricing contains outliers in the returns."));
- continue;
- }
-// Cumulative return
- double cumulativeReturn=prices.GetCumulativeReturn();
- if(cumulativeReturn<.10)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"Candidate cumulative returns below threshhold."));
- continue;
- }
-
-// Zacks Rank. This is for informational purposes for now but may further it's use in the future.
- ZacksRank zacksRank=ZacksRankDA.GetZacksRankOnOrBefore(symbol,tradeDate);
-
-// Apply the PEScreening last because there an option to permit the inclusion of the high PE candidates if we have no other available candidates.
-// The idea is to try to avoid high PE stocks as they are more likey to introduce drawdowns as backtests have shown.
- if(config.UseMaxPEScreen && !double.IsNaN(fundamental.PE) && fundamental.PE>config.MaxPE)
- {
- candidateViolations.Add(new CandidateViolation(symbol,"PE violation."));
- MomentumCandidate highPECandidate=new MomentumCandidate();
- highPECandidate.AnalysisDate=tradeDate;
- highPECandidate.Symbol=symbol;
- highPECandidate.CumReturn252=prices.GetCumulativeReturn();
- highPECandidate.DayCount=(int)MomentumGeneratorConstants.DayCount;
- highPECandidate.IDIndicator=IDIndicator.Calculate(prices);
- highPECandidate.Score=ScoreIndicator.Calculate(prices);
- highPECandidate.MaxDrawdown=prices.MaxDrawdown();
- highPECandidate.MaxUpside=prices.MaxUpside();
- highPECandidate.PE=fundamental.PE;
- highPECandidate.Beta=fundamental.Beta;
- highPECandidate.Velocity=velocity;
- highPECandidate.Volume=price.Volume;
- highPECandidate.Return1D=return1D;
- if(null!=zacksRank)highPECandidate.ZacksRank=zacksRank.Rank;
- highPECandidates.Add(highPECandidate);
- continue;
- }
-// *********************************************************************** C A N D I D A T E A C C E P T A N C E *******************************************************
-// At this point whatever remains is taken so initialize the candidate and add to list
- MomentumCandidate momentumCandidate=new MomentumCandidate();
- momentumCandidate.AnalysisDate=tradeDate;
- momentumCandidate.Symbol=symbol;
- momentumCandidate.CumReturn252=prices.GetCumulativeReturn();
- momentumCandidate.DayCount=(int)MomentumGeneratorConstants.DayCount;
- momentumCandidate.IDIndicator=IDIndicator.Calculate(prices);
- momentumCandidate.Score=ScoreIndicator.Calculate(prices);
- momentumCandidate.MaxDrawdown=prices.MaxDrawdown();
- momentumCandidate.MaxUpside=prices.MaxUpside();
- momentumCandidate.PE=fundamental.PE;
- momentumCandidate.Beta=fundamental.Beta;
- momentumCandidate.Velocity=velocity;
- momentumCandidate.Volume=price.Volume;
- momentumCandidate.Return1D=return1D;
- if(null!=zacksRank)momentumCandidate.ZacksRank=zacksRank.Rank;
- momentumCandidates.Add(momentumCandidate);
-
- } // for all symbols
-
- if(0!=candidateViolations.Count)
- {
- MDTrace.WriteLine(LogLevel.DEBUG,"**************** C A N D I D A T E S U M M A R Y ************************");
- IEnumerable> groups = candidateViolations.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 : {momentumCandidates.Count+candidateViolations.Count}"));
- MDTrace.WriteLine(LogLevel.DEBUG,String.Format($"Total Disqualified : {candidateViolations.Count}"));
- MDTrace.WriteLine(LogLevel.DEBUG,String.Format($"Total Eligible : {momentumCandidates.Count}"));
- MDTrace.WriteLine(LogLevel.DEBUG,"******************************************************************************************************");
-
-// ********************************************************* E N D C A N D I D A T E S E L E C T I O N C R I T E R I A ****************************************
-// If we wind up with less than the number of required candidates then check the StrictMaxPE
-// flag and, if allowed, add the highPECandidate (that we've accumulated but skipped) to the momentumCandidates ordering them by the Lowest PE
- if(!config.StrictMaxPE && momentumCandidates.Count0)
- {
- int takeCandidates=config.MaxPositions-momentumCandidates.Count;
- highPECandidates=new MomentumCandidates(highPECandidates.OrderBy(x=>x.PE).Take(takeCandidates).ToList());
- momentumCandidates.AddRange(highPECandidates);
- if(config.Verbose)MDTrace.WriteLine(LogLevel.DEBUG,String.Format("High PE Candidates,{0}",Utility.FromList((from MomentumCandidate momentumCandidate in highPECandidates select momentumCandidate.Symbol).ToList())));
- }
-
- QualityIndicator qualityIndicator=new QualityIndicator(config.QualityIndicatorType);
- if(qualityIndicator.Quality.Equals(QualityIndicator.QualityType.IDIndicator))
- {
- momentumCandidates=new MomentumCandidates((from MomentumCandidate momentumCandidate in momentumCandidates orderby momentumCandidate.IDIndicator ascending, momentumCandidate.CumReturn252 descending, momentumCandidate.Return1D descending, momentumCandidate.Volume descending select momentumCandidate).ToList());
- }
- else
- {
- momentumCandidates=new MomentumCandidates((from MomentumCandidate momentumCandidate in momentumCandidates orderby momentumCandidate.Score descending,momentumCandidate.CumReturn252 descending,momentumCandidate.Return1D descending,momentumCandidate.Volume descending select momentumCandidate).ToList());
- }
- MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MomentumGenertor.GenerateMomentum:{0} candidates",momentumCandidates.Count()));
- return momentumCandidates;
- }
-*/
}
}