BetaGenerator and some code cleanup
This commit is contained in:
@@ -748,7 +748,7 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
position.Comment = "Closed due to trailing stop.";
|
||||
HedgeCashBalance+=position.MarketValue;
|
||||
|
||||
// This tries to maintain a 10% margin in the hedge cash
|
||||
// This tries to maintain a hedgeCashMarginPercentDecimal margin in the hedge cash. In other words some % of the hedge gain -> Cash and some -> hedge cash, not allowing hedge cash to grow some margin beyond it's initial setting
|
||||
double hedgeCashMarginPercentDecimal=.10;
|
||||
double hedgeCashTreshholdAmount=Configuration.HedgeInitialCash*(1.00+hedgeCashMarginPercentDecimal);
|
||||
if(HedgeCashBalance > hedgeCashTreshholdAmount)
|
||||
@@ -764,13 +764,13 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
HedgeCashBalance=0.00;
|
||||
}
|
||||
|
||||
// Retain this original code for a while until happy with the hedge cash margin approach
|
||||
//if(HedgeCashBalance>Configuration.HedgeInitialCash)
|
||||
//{
|
||||
// CashBalance+=HedgeCashBalance-Configuration.HedgeInitialCash; // if we made gains on the hedge and the hedge cash would grow then put proceeds above the initial hedge cash in regualr cash
|
||||
// HedgeCashBalance=Configuration.HedgeInitialCash; // For example, let hedge proceeeds help the portfolio invest
|
||||
//}
|
||||
|
||||
|
||||
AllPositions.Add(position);
|
||||
closedPositions.Add(position);
|
||||
}
|
||||
@@ -1189,11 +1189,8 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
position.CumReturn252 = momentumCandidate.CumReturn252;
|
||||
position.IDIndicator = momentumCandidate.IDIndicator;
|
||||
position.Score=momentumCandidate.Score;
|
||||
position.MaxDrawdown = momentumCandidate.MaxDrawdown;
|
||||
position.MaxUpside = momentumCandidate.MaxUpside;
|
||||
position.PE = momentumCandidate.PE;
|
||||
position.Beta = momentumCandidate.Beta;
|
||||
position.ZacksRank = momentumCandidate.ZacksRank;
|
||||
position.Velocity = momentumCandidate.Velocity;
|
||||
position.Volume = momentumCandidate.Volume;
|
||||
position.Return1D = position.Return1D;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using MarketData.Utils;
|
||||
|
||||
namespace MarketData.Generator.MGSHMomentum
|
||||
@@ -52,6 +53,10 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
public bool UseEBITDAScreen{get;set;}
|
||||
public bool UseRevenuePerShareScreen{get;set;}
|
||||
|
||||
// BETA
|
||||
public bool UseBetaGenerator{get;set;} // If set then the model will use the internal beta generator. Otherwise it will use Beta from Fundamental data
|
||||
public int UseBetaGeneratorMonths{get;set;} // If UseBetaGenerator=true then UseBetaGeneratorMonths will prescribe the number of months over which to calculate the monthly beta
|
||||
|
||||
// If slope Beta Check is true then we compare the fundamental Beta to the threshhold value. If Beta>Threshhold AND the slope from the Benchmark LowPrice over BetaDays is <0 we reject
|
||||
public String Benchmark{get;set;}
|
||||
public bool UseLowSlopeBetaCheck{get;set;}
|
||||
@@ -105,6 +110,10 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
MaxPE=40;
|
||||
StrictMaxPE=false;
|
||||
|
||||
// Beta
|
||||
UseBetaGenerator=true; // The default setting is to calculate our own beta rather than use the beta from the fundamental data
|
||||
UseBetaGeneratorMonths=24; // The default number of months over which to calculate our monthly return stream for the beta generator
|
||||
|
||||
// Stop Limits
|
||||
UseStopLimits=false; // Flag to control the use of stop limits
|
||||
StopLimitRiskPercentDecimal=.17; // The per share risk to take when setting the initial stop. This was the best setting after running a suite of tests
|
||||
@@ -213,6 +222,9 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
|
||||
nvpCollection.Add(new NVP("MaxPricingExceptions",MaxPricingExceptions.ToString()));
|
||||
|
||||
nvpCollection.Add(new NVP("UseBetaGenerator",UseBetaGenerator.ToString()));
|
||||
nvpCollection.Add(new NVP("UseBetaGeneratorMonths",UseBetaGeneratorMonths.ToString()));
|
||||
|
||||
return nvpCollection;
|
||||
}
|
||||
public static MGSHConfiguration FromNVPCollection(NVPCollection nvpCollection)
|
||||
@@ -290,6 +302,13 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
{
|
||||
mgConfiguration.UseHedging=false;
|
||||
}
|
||||
|
||||
if(nvpDictionary.ContainsKey("UseBetaGenerator"))
|
||||
{
|
||||
mgConfiguration.UseBetaGenerator = nvpDictionary["UseBetaGenerator"].Get<bool>();
|
||||
mgConfiguration.UseBetaGeneratorMonths = nvpDictionary["UseBetaGeneratorMonths"].Get<int>();
|
||||
}
|
||||
|
||||
return mgConfiguration;
|
||||
}
|
||||
public void DisplayConfiguration()
|
||||
@@ -355,6 +374,10 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("HedgeCloseAboveSMANDays,{0}", HedgeCloseAboveSMANDays));
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("HedgeBandBreakCheckDays,{0}", HedgeBandBreakCheckDays));
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("HedgeATRMultiplier,{0}", HedgeATRMultiplier));
|
||||
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("UseBetaGenerator,{0}", UseBetaGenerator));
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("UseBetaGeneratorMonths,{0}", UseBetaGeneratorMonths));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,26 +23,32 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
public int DayCount{get;set;}
|
||||
public double IDIndicator{get;set;} // This is the IDIndicator methodology used for quality. This is the default methodology
|
||||
public double Score{get;set;} // This is the Score methodology used for quality. This one is taken from Andreas Clenow Momentum
|
||||
public double MaxDrawdown{get;set;}
|
||||
public double MaxUpside{get;set;}
|
||||
public double PE{get;set;}
|
||||
public double Beta{get;set;}
|
||||
public double Velocity{get;set;}
|
||||
public long Volume{get;set;}
|
||||
public double Return1D{get;set;}
|
||||
public double SharpeRatio{get;set;}
|
||||
public String ZacksRank{get;set;}
|
||||
|
||||
public static String Header()
|
||||
{
|
||||
StringBuilder sb=new StringBuilder();
|
||||
sb.Append("Symbol,AnalysisDate,Return,DayCount,IDIndicator,Score,MaxDrawdown,MaxUpside");
|
||||
sb.Append("Symbol,AnalysisDate,Return,DayCount,IDIndicator,Score");
|
||||
return sb.ToString();
|
||||
}
|
||||
public override String ToString()
|
||||
{
|
||||
StringBuilder sb=new StringBuilder();
|
||||
sb.Append(Symbol).Append(",").Append(AnalysisDate).Append(",").Append(Utility.FormatPercent(CumReturn252)).Append(",").Append(DayCount).Append(",").Append(IDIndicator).Append(",").Append(Score).Append(","). Append(Utility.FormatPercent(MaxDrawdown)).Append(",").Append(Utility.FormatPercent(MaxUpside));
|
||||
sb.Append(Symbol).Append(",").
|
||||
Append(AnalysisDate).
|
||||
Append(",").
|
||||
Append(Utility.FormatPercent(CumReturn252)).
|
||||
Append(",").Append(DayCount).
|
||||
Append(",").
|
||||
Append(IDIndicator).
|
||||
Append(",").
|
||||
Append(Score).
|
||||
Append(",");
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ using MarketData.Utils;
|
||||
using System.Linq;
|
||||
using MarketData.Numerical;
|
||||
using MarketData.Cache;
|
||||
using System.Configuration;
|
||||
|
||||
// Filename: MGSHMomentumGenerator.cs
|
||||
// Author:Sean Kessler
|
||||
@@ -15,6 +16,8 @@ using MarketData.Cache;
|
||||
// 2) Incorporates ability to buy a hedge position. This is configurable
|
||||
// 3) The model does not sell all positions at month end. Instead, it holds positions until they stop out. This is configurable
|
||||
|
||||
//BetaGenerator.Beta(symbol,tradeDate,cmtParams.BetaMonths); // beta months is 6
|
||||
|
||||
namespace MarketData.Generator.MGSHMomentum
|
||||
{
|
||||
/// <summary>Generate momentum selections - </summary>
|
||||
@@ -44,7 +47,6 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
bestCandidate=CandidateSelector.SelectBestCandidate(qualityIndicator,Utility.ToList(config.FallbackCandidateBestOf),config.FallbackCandidate,tradeDate);
|
||||
if(null!=bestCandidate)
|
||||
{
|
||||
ZacksRank zacksRank=ZacksRankDA.GetZacksRankOnOrBefore(bestCandidate.Symbol,tradeDate);
|
||||
MGSHMomentumCandidate momentumCandidate=new MGSHMomentumCandidate();
|
||||
momentumCandidate.Symbol=bestCandidate.Symbol;
|
||||
momentumCandidate.AnalysisDate=tradeDate;
|
||||
@@ -55,7 +57,6 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
momentumCandidate.PE=bestCandidate.PE;
|
||||
momentumCandidate.Beta=bestCandidate.Beta;
|
||||
momentumCandidate.Return1D=bestCandidate.Return1D;
|
||||
if(null!=zacksRank)momentumCandidate.ZacksRank=zacksRank.Rank;
|
||||
momentumCandidates=new MGSHMomentumCandidates();
|
||||
momentumCandidates.Add(momentumCandidate);
|
||||
}
|
||||
@@ -181,10 +182,23 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
double[] pricesArray=null;
|
||||
LeastSquaresResult leastSquaresResult;
|
||||
|
||||
// Beta - first capture the fundamental beta and then determine whether we will calculate our own
|
||||
double beta = fundamental.Beta;
|
||||
|
||||
if(config.UseBetaGenerator)
|
||||
{
|
||||
beta = BetaGenerator.Beta(symbol, config.UseBetaGeneratorMonths, false);
|
||||
if(double.IsNaN(beta))
|
||||
{
|
||||
candidateViolations.Add(new CandidateViolation(symbol,"No Beta violation."));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 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)
|
||||
if(config.UseLowSlopeBetaCheck && beta >= config.LowSlopeBetaThreshhold)
|
||||
{
|
||||
Prices benchmarkPrices=GBPriceCache.GetInstance().GetPrices(config.Benchmark,tradeDate,config.LowSlopeBetaDays);
|
||||
pricesArray=Numerics.ToDouble(benchmarkPrices.GetPricesLow());
|
||||
@@ -274,9 +288,6 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
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)
|
||||
@@ -289,14 +300,11 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
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.Beta=beta;
|
||||
highPECandidate.Velocity=velocity;
|
||||
highPECandidate.Volume=price.Volume;
|
||||
highPECandidate.Return1D=return1D;
|
||||
if(null!=zacksRank)highPECandidate.ZacksRank=zacksRank.Rank;
|
||||
highPECandidates.Add(highPECandidate);
|
||||
continue;
|
||||
}
|
||||
@@ -309,14 +317,11 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
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.Beta=beta;
|
||||
momentumCandidate.Velocity=velocity;
|
||||
momentumCandidate.Volume=price.Volume;
|
||||
momentumCandidate.Return1D=return1D;
|
||||
if(null!=zacksRank)momentumCandidate.ZacksRank=zacksRank.Rank;
|
||||
momentumCandidates.Add(momentumCandidate);
|
||||
|
||||
} // for all symbols
|
||||
|
||||
@@ -22,12 +22,9 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
CurrentPrice = position.CurrentPrice;
|
||||
Volume = position.Volume;
|
||||
Return1D = position.Return1D;
|
||||
ZacksRank = position.ZacksRank;
|
||||
CumReturn252 = position.CumReturn252;
|
||||
IDIndicator = position.IDIndicator;
|
||||
Score=position.Score;
|
||||
MaxDrawdown = position.MaxDrawdown;
|
||||
MaxUpside = position.MaxUpside;
|
||||
Velocity = position.Velocity;
|
||||
PE = position.PE;
|
||||
Beta = position.Beta;
|
||||
@@ -50,12 +47,9 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
position.CurrentPrice=positionToClone.CurrentPrice;
|
||||
position.Volume=positionToClone.Volume;
|
||||
position.Return1D=positionToClone.Return1D;
|
||||
position.ZacksRank=positionToClone.ZacksRank;
|
||||
position.CumReturn252=positionToClone.CumReturn252;
|
||||
position.IDIndicator=positionToClone.IDIndicator;
|
||||
position.Score=positionToClone.Score;
|
||||
position.MaxDrawdown=positionToClone.MaxDrawdown;
|
||||
position.MaxUpside=positionToClone.MaxUpside;
|
||||
position.Velocity=positionToClone.Velocity;
|
||||
position.PE=positionToClone.PE;
|
||||
position.Beta=positionToClone.Beta;
|
||||
@@ -80,12 +74,10 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
public double Return1D{get;set;}
|
||||
public double GainLoss{get{return MarketValue-Exposure;}}
|
||||
public double GainLossPcnt{get{return (MarketValue-Exposure)/Exposure;}}
|
||||
public String ZacksRank{get;set;}
|
||||
// public String ZacksRank{get;set;}
|
||||
public double CumReturn252{get;set;}
|
||||
public double IDIndicator{get;set;}
|
||||
public double Score{get;set;}
|
||||
public double MaxDrawdown{get;set;}
|
||||
public double MaxUpside{get;set;}
|
||||
public double Velocity{get;set;}
|
||||
public double PE{get;set;}
|
||||
public double Beta{get;set;}
|
||||
@@ -107,12 +99,9 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
nvpCollection.Add(new NVP("CurrentPrice",CurrentPrice.ToString()));
|
||||
nvpCollection.Add(new NVP("Volume",Volume.ToString()));
|
||||
nvpCollection.Add(new NVP("Return1D",Return1D.ToString()));
|
||||
nvpCollection.Add(new NVP("ZacksRank",ZacksRank));
|
||||
nvpCollection.Add(new NVP("CumReturn252",CumReturn252.ToString()));
|
||||
nvpCollection.Add(new NVP("IDIndicator",IDIndicator.ToString()));
|
||||
nvpCollection.Add(new NVP("Score",Score.ToString()));
|
||||
nvpCollection.Add(new NVP("MaxDrawdown",MaxDrawdown.ToString()));
|
||||
nvpCollection.Add(new NVP("MaxUpside",MaxUpside.ToString()));
|
||||
nvpCollection.Add(new NVP("Velocity",Velocity.ToString()));
|
||||
nvpCollection.Add(new NVP("PE",PE.ToString()));
|
||||
nvpCollection.Add(new NVP("Beta",Beta.ToString()));
|
||||
@@ -137,11 +126,8 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
position.CurrentPrice=nvpDictionary["CurrentPrice"].Get<double>();
|
||||
position.Volume=nvpDictionary["Volume"].Get<long>();
|
||||
position.Return1D=nvpDictionary["Return1D"].Get<long>();
|
||||
if(nvpDictionary.ContainsKey("ZacksRank"))position.ZacksRank=nvpDictionary["ZacksRank"].Get<String>();
|
||||
position.CumReturn252=nvpDictionary["CumReturn252"].Get<long>();
|
||||
position.IDIndicator=nvpDictionary["IDIndicator"].Get<double>();
|
||||
if(nvpDictionary.ContainsKey("MaxDrawdown"))position.MaxDrawdown=nvpDictionary["MaxDrawdown"].Get<double>();
|
||||
if(nvpDictionary.ContainsKey("MaxUpside"))position.MaxUpside=nvpDictionary["MaxUpside"].Get<double>();
|
||||
position.Velocity=nvpDictionary["Velocity"].Get<double>();
|
||||
position.PE=nvpDictionary["PE"].Get<double>();
|
||||
position.Beta=nvpDictionary["Beta"].Get<double>();
|
||||
@@ -169,7 +155,7 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
{
|
||||
if (Utility.IsEpoch(SellDate) && double.IsNaN(CurrentPrice))
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0},{1},{2},{3},{4},{5},{6},N/A,N/A,N/A,N/A,N/A,{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18}",
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0},{1},{2},{3},{4},{5},{6},N/A,N/A,N/A,N/A,N/A,{7},{8},{9},{10},{11},{12},{13},{14},{15},{16}",
|
||||
Symbol,
|
||||
Utility.DateTimeToStringMMHDDHYYYY(PurchaseDate),
|
||||
Shares,
|
||||
@@ -180,8 +166,6 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
Utility.AddQuotes(Utility.FormatPercent(CumReturn252)),
|
||||
Utility.AddQuotes(Utility.FormatNumber(IDIndicator)),
|
||||
Utility.AddQuotes(Utility.FormatNumber(Score)),
|
||||
Utility.AddQuotes(Utility.FormatPercent(MaxDrawdown)),
|
||||
Utility.AddQuotes(Utility.FormatPercent(MaxUpside)),
|
||||
Utility.AddQuotes(Utility.FormatPercent(Velocity)),
|
||||
Utility.AddQuotes(Utility.FormatNumber(PE)),
|
||||
Utility.AddQuotes(Utility.FormatNumber(Beta)),
|
||||
@@ -193,7 +177,7 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
}
|
||||
else
|
||||
{
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21},{22},{23}",
|
||||
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12},{13},{14},{15},{16},{17},{18},{19},{20},{21}",
|
||||
Symbol,
|
||||
Utility.DateTimeToStringMMHDDHYYYY(PurchaseDate),
|
||||
Shares,
|
||||
@@ -209,8 +193,6 @@ namespace MarketData.Generator.MGSHMomentum
|
||||
Utility.AddQuotes(Utility.FormatPercent(CumReturn252)),
|
||||
Utility.AddQuotes(Utility.FormatNumber(IDIndicator)),
|
||||
Utility.AddQuotes(Utility.FormatNumber(Score)),
|
||||
Utility.AddQuotes(Utility.FormatPercent(MaxDrawdown)),
|
||||
Utility.AddQuotes(Utility.FormatPercent(MaxUpside)),
|
||||
Utility.AddQuotes(Utility.FormatPercent(Velocity)),
|
||||
Utility.AddQuotes(Utility.FormatNumber(PE)),
|
||||
Utility.AddQuotes(Utility.FormatNumber(Beta)),
|
||||
|
||||
Reference in New Issue
Block a user