Add CMTRend

This commit is contained in:
2025-04-08 19:25:43 -04:00
parent eec147b974
commit 70340bdd25
18 changed files with 3671 additions and 26 deletions

View File

@@ -0,0 +1,202 @@
using MarketData.Generator.CMTrend;
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MarketData
{
/// <summary>
/// This model is based on Mark Minervini
/// </summary>
public static class CMTrendHelper
{
/// <summary>
/// CMTSESSION /SESSIONFILE:{pathfilename}
/// </summary>
public static void HandleCMTSession(CommandArgs commandArgs)
{
if (!commandArgs.Has("SESSIONFILE")) {MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Missing SESSIONFILE"));return;}
CMTTrendModel trendModel=new CMTTrendModel();
trendModel.DisplaySession(commandArgs.Coalesce<String>("SESSIONFILE"));
}
/// <summary>
/// RUNCMTREND /MODE:DAILY|BACKTEST|RUNTRENDTEMPLATE|ENTRYTEST /SYMBOL:{for mode ANALYZE,ENTRYTEST} /TRADEDATE:{for mode DAILY,RUNTRENDTEMPLATE) /STARTDATE:(for mode BACKTEST,ENTRYTEST) /ENDDATE:(for mode BACKTEST) /INITIALCASH: /SESSIONFILE: /MAXOPENPOSITIONS: /MAXDAILYPOSITIONS: Runs Mark Minervini trend
/// VALID ARGUMENTS FOR /MODE:BACKTEST ARE /SELLATENDOFSIMULATION: /STARTDATE: /ENDDATE: /SESSIONFILE: /MAXDAILYPOSITIONS: /MAXOPENPOSITIONS: /BENCHMARKMOVINGAVERAGEDAYS: /BENCHMARKMOVINGAVERAGEHORIZON
/// VALID ARGUMENTS FOR /MODE:BACKTEST CONTD., /POSITIONRISKPERCENTDECIMAL: /ENTRYTYPE:OverExtended,MVP,PriceTrend,VolumeTrend,RVOL /USEPROFITMAXIMIZATION:{TRUE|FALSE} /USEPROFITMAXIMIZATIONEXPRESSION:{string}
/// VALID ARGUMENTS FOR /MODE:BACKTEST CONTD., /POSITIONRISKPERCENTDECIMAL: /ENTRYTYPE:OverExtended,MVP,PriceTrend,VolumeTrend,RVOL /USEPROFITMAXIMIZATION:TRUE /USEPROFITMAXIMIZATIONEXPRESSION:\"R_THRESSHOLD=4;MAX_ATR=3;MAX_R=10;FACTOR=MAX_ATR/MAX_R;MULTIPLIER=MAX_ATR;IF(RMultiple>R_THRESSHOLD){MULTIPLIER=FACTOR*RMultiple;}\"
/// VALID ARGUMENTS FOR /MODE:BACKTEST CONTD., /USEPOSITIONSIZINGSTRATEGY:{TRUE|FALSE} /USEPOSITIONSIZINGSTRATEGYSTRATEGY:{TotalRisk:EqualWeight,Formula} /USEPOSITIONSIZINGSTRATEGYFORMULA:{Formula}
/// VALID ARGUMENTS FOR /MODE:BACKTEST CONTD., /USETRADEONLYSECTORS:{TRUE|FALSE} /USETRADEONLYSECTORSSECTORS:Healthcare,Technology,Basic Materials,Consumer Defensive,Industrials
/// /BENCHMARKMOVINGAVERAGEDAYS: (i.e.) 200, 100, 55
/// /BENCHMARKMOVINGAVERAGEHORIZON: (i.e.) 5
/// </summary>
/// <param name="commandArgs"></param>
public static void HandleRunCMTrend(CommandArgs commandArgs)
{
String mode;
if(!commandArgs.Has("MODE"))
{
if(!commandArgs.Has("MODE")) MDTrace.WriteLine(LogLevel.DEBUG,"MODE is a required paramater.");
MDTrace.WriteLine(LogLevel.DEBUG,"RUNMMTREND /MODE:DAILY|BACKTEST|RUNTRENDTEMPLATE|ANALYZE|DISPLAY|CLOSEPOSITION /SELLDATE:{CLOSEPOSITION} /PRICE:{CLOSEPOSITION} /SYMBOL:{for mode ANALYZE,CLOSEPOSITION} /TRADEDATE:{for mode DAILY,RUNTRENDTEMPLATE,ANALYZE,CLOSEPOSITION) /STARTDATE:(for mode BACKTEST) /ENDDATE:(for mode BACKTEST) /INITIALCASH: /SESSIONFILE: MAXOPENPOSITIONS: /MAXDAILYPOSITIONS: Runs Mark Minervini trend");
return;
}
mode=commandArgs.Get<String>("MODE");
if("ENTRYTEST".Equals(mode))
{
CMTParams cmtParams=new CMTParams();
if(!commandArgs.Has("SYMBOL")||!commandArgs.Has("STARTDATE"))
{
if(!commandArgs.Contains("SYMBOL")) MDTrace.WriteLine(LogLevel.DEBUG,"SYMBOL is a required parameter when MODE=ENTRYTEST");
if(!commandArgs.Contains("STARTDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"STARTDATE is a required parameter when MODE=ENTRYTEST");
return;
}
CMTTrendModel trendModel=new CMTTrendModel();
trendModel.EntryTest(commandArgs.Get<String>("SYMBOL"),commandArgs.Get<DateTime>("STARTDATE"));
}
else if("CLOSEPOSITION".Equals(mode))
{
CMTParams cmtParams=new CMTParams();
if(!commandArgs.Has("PURCHASEDATE,SYMBOL,SESSIONFILE,PRICE,SELLDATE"))
{
if(!commandArgs.Contains("PURCHASEDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"PURCHASEDATE is a required parameter when MODE=CLOSEPOSITION");
if(!commandArgs.Contains("SYMBOL")) MDTrace.WriteLine(LogLevel.DEBUG,"SYMBOL is a required parameter when MODE=CLOSEPOSITION");
if(!commandArgs.Contains("SESSIONFILE")) MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE is a required parameter when MODE=CLOSEPOSITION");
if(!commandArgs.Contains("PRICE")) MDTrace.WriteLine(LogLevel.DEBUG,"PRICE is a required parameter when MODE=CLOSEPOSITION");
if(!commandArgs.Contains("SELLDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"SELLDATE is a required parameter when MODE=CLOSEPOSITION");
return;
}
CMTTrendModel trendModel=new CMTTrendModel();
trendModel.ClosePosition(commandArgs.Get<String>("SYMBOL"),commandArgs.Get<DateTime>("PURCHASEDATE"),commandArgs.Get<DateTime>("SELLDATE"),commandArgs.Get<double>("PRICE"),commandArgs.Get<String>("SESSIONFILE"));
}
else if("DAILY".Equals(mode))
{
CMTParams cmtParams=new CMTParams();
if(!commandArgs.Has("TRADEDATE,SESSIONFILE"))
{
if(!commandArgs.Contains("TRADEDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"TRADEDATE is a required parameter when MODE=DAILY");
if(!commandArgs.Contains("SESSIONFILE")) MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE is a required parameter when MODE=DAILY");
return;
}
if(commandArgs.Contains("INITIALCASH")) cmtParams.InitialCash=commandArgs.Get<double>("INITIALCASH");
if(commandArgs.Contains("MAXDAILYPOSITIONS")) cmtParams.MaxDailyPositions=commandArgs.Get<int>("MAXDAILYPOSITIONS");
if(commandArgs.Contains("MAXOPENPOSITIONS")) cmtParams.MaxOpenPositions=commandArgs.Get<int>("MAXOPENPOSITIONS");
if(commandArgs.Has("ONLYTRADESYMBOLS")) cmtParams.OnlyTradeSymbols=commandArgs.Get<String>("ONLYTRADESYMBOLS");
if(commandArgs.Contains("POSITIONRISKPERCENTDECIMAL"))
{
cmtParams.PositionRiskPercentDecimal=commandArgs.Get<double>("POSITIONRISKPERCENTDECIMAL");
}
if(commandArgs.Contains("ENTRYTYPE"))
{
List<String> entryTypes=Utility.ToList(commandArgs.Get<String>("ENTRYTYPE"));
List<String> constraints=new List<String> { "OVEREXTENDED","MVP","NARROWRANGE","MACD","PRICETREND","VOLUMETREND" };
bool results=entryTypes.All(i => constraints.ContainsIgnoreCase(i));
if(!results)
{
MDTrace.WriteLine(LogLevel.DEBUG,"ENTRYTYPE must consist of one or more OVEREXTENDED, MVP, NarrowRange, MACD, PriceTrend, VolumeTrend");
return;
}
cmtParams.EntryType=commandArgs.Get<String>("ENTRYTYPE");
}
CMTTrendModel trendModel=new CMTTrendModel();
if(commandArgs.Contains("USETRADEONLYSECTORS"))
{
cmtParams.UseTradeOnlySectors=commandArgs.Get<bool>("USETRADEONLYSECTORS");
if(cmtParams.UseTradeOnlySectors)
{
cmtParams.UseTradeOnlySectorsSectors=commandArgs.Get<String>("USETRADEONLYSECTORSSECTORS");
}
}
CMTTrendModelResult result=trendModel.RunDaily(commandArgs.Get<DateTime>("TRADEDATE"),commandArgs.Get<String>("SESSIONFILE"),cmtParams);
}
else if("BACKTEST".Equals(mode))
{
CMTParams cmtParams=new CMTParams();
bool sellAtEndOfSimulation=true;
if(!commandArgs.Has("STARTDATE,ENDDATE,SESSIONFILE"))
{
if(!commandArgs.Contains("STARTDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"STARTDATE is a required parameter");
if(!commandArgs.Contains("ENDDATE")) MDTrace.WriteLine(LogLevel.DEBUG,"ENDDATE is a required parameter");
if(!commandArgs.Contains("SESSIONFILE")) MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE is a required parameter");
return;
}
CMTTrendModel trendModel=new CMTTrendModel();
if(commandArgs.Contains("USETRADEONLYSECTORS"))
{
cmtParams.UseTradeOnlySectors=commandArgs.Get<bool>("USETRADEONLYSECTORS");
if(cmtParams.UseTradeOnlySectors)
{
cmtParams.UseTradeOnlySectorsSectors=commandArgs.Get<String>("USETRADEONLYSECTORSSECTORS");
}
}
if(commandArgs.Contains("USEPROFITMAXIMIZATION"))
{
cmtParams.UseProfitMaximization=commandArgs.Get<bool>("USEPROFITMAXIMIZATION");
if(commandArgs.Contains("USEPROFITMAXIMIZATIONEXPRESSION"))
{
cmtParams.UseProfitMaximizationExpression=commandArgs.Get<String>("USEPROFITMAXIMIZATIONEXPRESSION");
}
}
if(commandArgs.Contains("MAXDAILYPOSITIONS")) cmtParams.MaxDailyPositions=commandArgs.Get<int>("MAXDAILYPOSITIONS");
if(commandArgs.Contains("MAXOPENPOSITIONS")) cmtParams.MaxOpenPositions=commandArgs.Get<int>("MAXOPENPOSITIONS");
if(commandArgs.Contains("BENCHMARKMOVINGAVERAGEDAYS")) cmtParams.BenchmarkMovingAverageDays=commandArgs.Get<int>("BENCHMARKMOVINGAVERAGEDAYS");
if(commandArgs.Contains("BENCHMARKMOVINGAVERAGEHORIZON")) cmtParams.BenchmarkMovingAverageHorizon=commandArgs.Get<int>("BENCHMARKMOVINGAVERAGEHORIZON");
if(commandArgs.Has("ONLYTRADESYMBOLS")) cmtParams.OnlyTradeSymbols=commandArgs.Get<String>("ONLYTRADESYMBOLS");
if(commandArgs.Contains("POSITIONRISKPERCENTDECIMAL"))
{
cmtParams.PositionRiskPercentDecimal=commandArgs.Get<double>("POSITIONRISKPERCENTDECIMAL");
}
if(commandArgs.Contains("ENTRYTYPE"))
{
List<String> entryTypes=Utility.ToList(commandArgs.Get<String>("ENTRYTYPE"));
List<String> constraints=new List<String> { "OVEREXTENDED","MVP","NARROWRANGE","MACD","PRICETREND","VOLUMETREND" };
bool results=entryTypes.All(i => constraints.ContainsIgnoreCase(i));
if(!results)
{
MDTrace.WriteLine(LogLevel.DEBUG,"ENTRYTYPE must consist of one or more OVEREXTENDED, MVP, NarrowRange, MACD, PriceTrend, VolumeTrend");
return;
}
cmtParams.EntryType=commandArgs.Get<String>("ENTRYTYPE");
}
if(commandArgs.Contains("SELLATENDOFSIMULATION"))
{
sellAtEndOfSimulation=commandArgs.Get<bool>("SELLATENDOFSIMULATION");
}
CMTTrendModelResult result=trendModel.RunBacktestMode(commandArgs.Get<DateTime>("STARTDATE"),commandArgs.Get<DateTime>("ENDDATE"),sellAtEndOfSimulation,commandArgs.Get<String>("SESSIONFILE"),cmtParams);
}
else if("DISPLAY".Equals(mode))
{
if(!commandArgs.Contains("SESSIONFILE")) { MDTrace.WriteLine(LogLevel.DEBUG,"SESSIONFILE is a required parameter"); return; }
CMTTrendModel trendModel=new CMTTrendModel();
trendModel.DisplaySession(commandArgs.Get<String>("SESSIONFILE"));
}
else if("RUNTRENDTEMPLATE".Equals(mode))
{
if(!commandArgs.Contains("TRADEDATE"))
{
MDTrace.WriteLine(LogLevel.DEBUG,"TRADEDATE is a required parameter when MODE=DAILY");
return;
}
CMTTrendModel trendModel=new CMTTrendModel();
trendModel.RunTrendTemplate(commandArgs.Get<DateTime>("TRADEDATE"));
}
else
{
MDTrace.WriteLine(LogLevel.DEBUG,"RUNCMTREND /MODE:DAILY|BACKTEST /TRADEDATE:{for mode DAILY) /STARTDATE:(for mode BACKTEST) /ENDDATE:(for mode BACKTEST) /INITIALCASH: /SESSIONFILE: /MAXPOSITIONS Runs Mark Minervini trend");
}
return;
}
}
}

View File

@@ -15,6 +15,29 @@ namespace MarketData.Services
{
private Dictionary<String, Func<CommandArgs,Task>> tasks = new Dictionary<String,Func<CommandArgs,Task>>();
/// <summary>
/// DisplayUsage
/// </summary>
public static void DisplayUsage()
{
MDTrace.WriteLine(LogLevel.DEBUG,$"USAGE");
MDTrace.WriteLine(LogLevel.DEBUG,$"LOADHEADLINESWATCHLIST");
MDTrace.WriteLine(LogLevel.DEBUG,$"LOADPREMARKETDATA");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATEDAILY2 /DATE:");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATELATESTPRICEOPENPOSITIONS");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATELATESTPRICEWATCHLIST /WATCHLIST:");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATELATESTANALYSTRATINGS");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATEANALYSTRATINGS");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATESECFILINGSWATCHLIST /WATCHLIST:");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATECOMPANYPROFILES");
MDTrace.WriteLine(LogLevel.DEBUG,"ECHO {param1} {param2} {param(n)");
MDTrace.WriteLine(LogLevel.DEBUG,"MGSHSESSION /SESSIONFILE:");
MDTrace.WriteLine(LogLevel.DEBUG,"MGSHRUNBACKTEST /USEHEDGING: /HEDGEINITIALCASH: /USESTOPLIMITS: /KEEPSLOTPOSITIONS: /STARTDATE: /MAXPOSITIONS: /INITIALCASH: /HOLDINGPERIOD: /{ENDDATE}: /SESSIONFILE: ");
MDTrace.WriteLine(LogLevel.DEBUG,"MGSHRUNDAILY /SESSIONFILE: /TRADEDATE:");
MDTrace.WriteLine(LogLevel.DEBUG,"RUNCMTREND /MODE:DAILY|BACKTEST|RUNTRENDTEMPLATE|ENTRYTEST /SYMBOL:{for mode ANALYZE,ENTRYTEST} /TRADEDATE:{for mode DAILY,RUNTRENDTEMPLATE) /STARTDATE:(for mode BACKTEST,ENTRYTEST) /ENDDATE:(for mode BACKTEST) /INITIALCASH: /SESSIONFILE: /MAXOPENPOSITIONS: /MAXDAILYPOSITIONS: Runs Mark Minervini trend");
MDTrace.WriteLine(LogLevel.DEBUG,"CMTSESSION /SESSIONFILE:{pathfilename} Runs Mark Minervini trend display session");
}
/// <summary>
/// This is the main entry point
/// </summary>
@@ -37,6 +60,8 @@ namespace MarketData.Services
tasks.Add("MGSHSESSION",TaskMGSHSession);
tasks.Add("MGSHRUNBACKTEST",TaskMGSHRunBacktest);
tasks.Add("MGSHRUNDAILY",TaskMGSHRunDaily);
tasks.Add("RUNCMTREND",TaskRunCMTrend);
tasks.Add("CMTSESSION",TaskCMTSession);
tasks.Add("ECHO",TaskEcho);
GlobalConfig.Instance.Configuration = configuration; // This call sets up configuration stuff so it needs to be first.
@@ -186,6 +211,18 @@ namespace MarketData.Services
await Task.FromResult(true);
}
public async Task TaskRunCMTrend(CommandArgs commandArgs)
{
CMTrendHelper.HandleRunCMTrend(commandArgs);
await Task.FromResult(true);
}
public async Task TaskCMTSession(CommandArgs commandArgs)
{
CMTrendHelper.HandleCMTSession(commandArgs);
await Task.FromResult(true);
}
// *********************************************************************************************************************************************************
// ******************************************************************* E N D T A S K S ********************************************************************
// *********************************************************************************************************************************************************
@@ -210,28 +247,6 @@ namespace MarketData.Services
return true;
}
// *********************************************************************************************************************************
// *********************************************************************************************************************************
// *********************************************************************************************************************************
public static void DisplayUsage()
{
MDTrace.WriteLine(LogLevel.DEBUG,$"USAGE");
MDTrace.WriteLine(LogLevel.DEBUG,$"LOADHEADLINESWATCHLIST");
MDTrace.WriteLine(LogLevel.DEBUG,$"LOADPREMARKETDATA");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATEDAILY2 /DATE:");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATELATESTPRICEOPENPOSITIONS");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATELATESTPRICEWATCHLIST /WATCHLIST:");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATELATESTANALYSTRATINGS");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATEANALYSTRATINGS");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATESECFILINGSWATCHLIST /WATCHLIST:");
MDTrace.WriteLine(LogLevel.DEBUG,"UPDATECOMPANYPROFILES");
MDTrace.WriteLine(LogLevel.DEBUG,"ECHO {param1} {param2} {param(n)");
MDTrace.WriteLine(LogLevel.DEBUG,"MGSHSESSION /SESSIONFILE:");
MDTrace.WriteLine(LogLevel.DEBUG,"MGSHRUNBACKTEST /USEHEDGING: /HEDGEINITIALCASH: /USESTOPLIMITS: /KEEPSLOTPOSITIONS: /STARTDATE: /MAXPOSITIONS: /INITIALCASH: /HOLDINGPERIOD: /{ENDDATE}: /SESSIONFILE: ");
MDTrace.WriteLine(LogLevel.DEBUG,"MGSHRUNDAILY /SESSIONFILE: /TRADEDATE:");
}
// **********************************************************************************************************************************************
// ************************************************* U P D A T E D A I L Y 2 M E T H O D S ***************************************************
// **********************************************************************************************************************************************

View File

@@ -0,0 +1,18 @@
using MarketData.MarketDataModel;
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.CMTrend
{
public class ActivePositions:Positions
{
public ActivePositions()
{
}
}
}

View File

@@ -0,0 +1,129 @@
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.CMTrend
{
public class CMTCandidates : List<CMTCandidate>
{
public CMTCandidates()
{
}
public CMTCandidates(List<CMTCandidate> cmtCandidates)
{
foreach(CMTCandidate cmtCandidate in cmtCandidates) Add(cmtCandidate);
}
public NVPCollections ToNVPCollections()
{
NVPCollections nvpCollections=new NVPCollections();
foreach(CMTCandidate candidate in this)
{
nvpCollections.Add(candidate.ToNVPCollection());
}
return nvpCollections;
}
public static CMTCandidates FromNVPCollections(NVPCollections nvpCollections)
{
CMTCandidates candidates=new CMTCandidates();
foreach(NVPCollection nvpCollection in nvpCollections)
{
candidates.Add(CMTCandidate.FromNVPCollection(nvpCollection));
}
return candidates;
}
public void AddFromNVPCollection(NVPCollection nvpCollection)
{
Add(CMTCandidate.FromNVPCollection(nvpCollection));
}
public new void Sort()
{
List<CMTCandidate> candidates=new CMTCandidates((from CMTCandidate mmCandidate in this select mmCandidate).OrderByDescending(x => x.Score).ToList());
this.Clear();
this.AddRange(candidates);
}
}
public class CMTCandidate
{
public CMTCandidate()
{
Violation=false;
}
public String Symbol { get; set; }
public DateTime AnalysisDate { get; set; }
public double EPSSlope { get; set; }
public double ProfitMarginSlope { get; set; }
public double PriceSlope { get; set; }
public double Volatility { get; set; }
public long Volume { get; set; }
public double RSquared{get;set;}
public double Beta{get;set;}
public int BetaMonths{get;set;}
public bool Violation { get; set; }
public double Slope { get; set; }
public double Score { get; set; }
public double AnnualizedReturn { get; set; }
public double SharpeRatio { get; set; }
public String Reason { get; set; }
public virtual NVPCollection ToNVPCollection()
{
NVPCollection nvpCollection=new NVPCollection();
nvpCollection.Add(new NVP("Symbol",Symbol.ToString()));
nvpCollection.Add(new NVP("AnalysisDate",AnalysisDate.ToString()));
if(!double.IsNaN(EPSSlope)) nvpCollection.Add(new NVP("EPSSlope",EPSSlope.ToString()));
if(!double.IsNaN(ProfitMarginSlope)) nvpCollection.Add(new NVP("ProfitMarginSlope",ProfitMarginSlope.ToString()));
if(!double.IsNaN(PriceSlope)) nvpCollection.Add(new NVP("PriceSlope",PriceSlope.ToString()));
if(!double.IsNaN(Volatility)) nvpCollection.Add(new NVP("Volatility",Volatility.ToString()));
nvpCollection.Add(new NVP("Volume",Volume.ToString()));
nvpCollection.Add(new NVP("Violation",Violation.ToString()));
if(!double.IsNaN(Slope)) nvpCollection.Add(new NVP("Slope",Slope.ToString()));
if(!double.IsNaN(Score)) nvpCollection.Add(new NVP("Score",Score.ToString()));
if(!double.IsNaN(AnnualizedReturn)) nvpCollection.Add(new NVP("AnnualizedReturn",AnnualizedReturn.ToString()));
if(!double.IsNaN(SharpeRatio)) nvpCollection.Add(new NVP("SharpeRatio",SharpeRatio.ToString()));
if(!double.IsNaN(RSquared)) nvpCollection.Add(new NVP("RSquared",RSquared.ToString()));
nvpCollection.Add(new NVP("BetaMonths",BetaMonths.ToString()));
nvpCollection.Add(new NVP("Beta",Beta.ToString()));
if(null!=Reason) nvpCollection.Add(new NVP("Reason",Reason.ToString()));
return nvpCollection;
}
public static CMTCandidate FromNVPCollection(NVPCollection nvpCollection)
{
CMTCandidate candidate=new CMTCandidate();
NVPDictionary nvpDictionary=nvpCollection.ToDictionary();
if(nvpDictionary.ContainsKey("Symbol")) candidate.Symbol=nvpDictionary["Symbol"].Get<String>();
if(nvpDictionary.ContainsKey("AnalysisDate")) candidate.AnalysisDate=nvpDictionary["AnalysisDate"].Get<DateTime>();
if(nvpDictionary.ContainsKey("EPSSlope")) candidate.EPSSlope=nvpDictionary["EPSSlope"].Get<double>();
if(nvpDictionary.ContainsKey("ProfitMarginSlope")) candidate.ProfitMarginSlope=nvpDictionary["ProfitMarginSlope"].Get<double>();
if(nvpDictionary.ContainsKey("PriceSlope")) candidate.PriceSlope=nvpDictionary["PriceSlope"].Get<double>();
if(nvpDictionary.ContainsKey("Volatility")) candidate.Volatility=nvpDictionary["Volatility"].Get<double>();
if(nvpDictionary.ContainsKey("Volume")) candidate.Volume=nvpDictionary["Volume"].Get<long>();
if(nvpDictionary.ContainsKey("Violation")) candidate.Violation=nvpDictionary["Violation"].Get<bool>();
if(nvpDictionary.ContainsKey("Slope")) candidate.Slope=nvpDictionary["Slope"].Get<double>();
if(nvpDictionary.ContainsKey("Score")) candidate.Score=nvpDictionary["Score"].Get<double>();
if(nvpDictionary.ContainsKey("AnnualizedReturn")) candidate.AnnualizedReturn=nvpDictionary["AnnualizedReturn"].Get<double>();
if(nvpDictionary.ContainsKey("SharpeRatio")) candidate.SharpeRatio=nvpDictionary["SharpeRatio"].Get<double>();
if(nvpDictionary.ContainsKey("RSquared")) candidate.RSquared=nvpDictionary["RSquared"].Get<double>();
if(nvpDictionary.ContainsKey("BetaMonths")) candidate.BetaMonths=nvpDictionary["BetaMonths"].Get<int>();
if(nvpDictionary.ContainsKey("Beta")) candidate.Beta=nvpDictionary["Beta"].Get<double>();
if(nvpDictionary.ContainsKey("Reason")) candidate.Reason=nvpDictionary["Reason"].Get<String>();
return candidate;
}
public static String Header()
{
StringBuilder sb=new StringBuilder();
sb.Append("Symbol,AnalysisDate,PriceSlope,ProfitMarginSlope,EPSSlope,Volatility,Volume,Slope,Score,AnnualizedReturn,SharpeRatio,RSquared,Beta,BetaMonths");
return sb.ToString();
}
public override String ToString()
{
StringBuilder sb=new StringBuilder();
sb.Append(Symbol).Append(",").Append(AnalysisDate.ToShortDateString()).Append(",").Append(PriceSlope).Append(",").Append(ProfitMarginSlope).Append(",").Append(EPSSlope).Append(",").Append(Volatility).Append(",").Append(Volume).Append(",").Append(Slope).Append(",").Append(Score).Append(",").Append(AnnualizedReturn).Append(",").Append(SharpeRatio).Append(",");
sb.Append(RSquared).Append(",").Append(Beta).Append(",").Append(BetaMonths);
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,438 @@
using MarketData.Cache;
using MarketData.DataAccess;
using MarketData.Generator.MovingAverage;
using MarketData.MarketDataModel;
using MarketData.Numerical;
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
namespace MarketData.Generator.CMTrend
{
public class CMTCandidateGenerator
{
private static readonly int PRICING_DAYS=252;
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)
{
CMTCandidate cmtCandidate=new CMTCandidate();
try
{
// Check MarketCap
Fundamental fundamental=FundamentalDA.GetFundamentalMaxDate(symbol,tradeDate);
if(null==fundamental)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("No fundamental for {0}.",symbol);
return cmtCandidate;
}
if(!(fundamental.MarketCap>=cmtParams.MarketCapLowerLimit))
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("MarketCapLowerLimit constraint violation for {0}.",symbol);
return cmtCandidate;
}
// Check if the symbol is held in any open positions
if(null!=symbolsHeld&&symbolsHeld.Any(x => x.Equals(symbol, StringComparison.CurrentCultureIgnoreCase)))
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("{0} is already held.",symbol);
return cmtCandidate;
}
// No trade symbols
if(null!=cmtParams.NoTradeSymbolsList&&cmtParams.NoTradeSymbolsList.Any(x => x.Equals(symbol, StringComparison.CurrentCultureIgnoreCase)))
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("{0} is in the No-Trade list.",symbol);
return cmtCandidate;
}
// Equity check
CompanyProfile companyProfile=CompanyProfileDA.GetCompanyProfile(symbol);
if(null==companyProfile)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("No company profile found for {0}.",symbol);
return cmtCandidate;
}
if(!companyProfile.IsEquity)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("{0} is not an equity. {1}.",symbol,companyProfile.SecurityType);
return cmtCandidate;
}
// Sector Check
if(cmtParams.UseTradeOnlySectors)
{
List<String> validSectors=Utility.ToList(cmtParams.UseTradeOnlySectorsSectors);
if(null==companyProfile.Sector)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Invalid sector for {0}. Found {1} expected one of {2}.",symbol,null==companyProfile.Sector?"(Null)":companyProfile.Sector,Utility.ListToString(validSectors.ToList<String>()));
return cmtCandidate;
}
if(!validSectors.Any(x => x.Equals(companyProfile.Sector)))
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Invalid sector for {0}. Found {1} expected one of {2}.",symbol,null==companyProfile.Sector?"(Null)":companyProfile.Sector,Utility.ListToString(validSectors.ToList<String>()));
return cmtCandidate;
}
}
// setup for trend analysis
Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,tradeDate,PRICING_DAYS);
if(null==prices||prices.Count<PRICING_DAYS)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason=String.Format("Insufficient pricing history, {0} days required.",PRICING_DAYS);
return cmtCandidate;
}
// Current Price Check
Price currentPrice=prices[0];
if(currentPrice.Date!=tradeDate)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="pricing date!=trade date.";
return cmtCandidate;
}
// Liquidity check - if any day has volume < MinVolume then we reject it
int belowThreshholdVolumeCount=(from Price xPrice in prices where xPrice.Volume<cmtParams.MinVolume select xPrice).Count();
if(cmtParams.LiquidityCheck&&belowThreshholdVolumeCount>0)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason=String.Format("Insufficient liquidity.");
return cmtCandidate;
}
// Setup for the moving averages checks
Prices prices50=new Prices(prices.Take(50).ToList());
Prices prices15=new Prices(prices.Take(15).ToList());
Prices prices150=new Prices(prices.Take(150).ToList());
Prices prices200=new Prices(prices.Take(200).ToList());
DMAPrices dma50Prices=MovingAverageGenerator.GenerateMovingAverage(prices50,prices50.Count);
DMAPrices dma150Prices=MovingAverageGenerator.GenerateMovingAverage(prices150,prices150.Count);
DMAPrices dma200Prices=MovingAverageGenerator.GenerateMovingAverage(prices200,prices200.Count);
double dma50Close=dma50Prices[0].AVGPrice;
double dma150Close=dma150Prices[0].AVGPrice;
double dma200Close=dma200Prices[0].AVGPrice;
double volatility=prices15.Volatility();
// Trend #1 check. Check that current price is greater than 150 day moving average and current price is greater than 200 day moving average
if(currentPrice.Close<dma150Close)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#1 Violation : currentPrice.Close<=dma150Close.";
return cmtCandidate;
}
if(currentPrice.Close<dma200Close)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason="Trend#1 Violation : currentPrice.Close<=dma200Close.";
return cmtCandidate;
}
// Trend #2 check. Check that 150 day moving average is greater than the 200 day moving average
if(dma150Close<dma200Close)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#2 Violation : dma150Close<=dma200Close.";
return cmtCandidate;
}
// Trend #4 check : The 50 day moving average must be greater than the 150 day moving average
if(dma50Close<=dma150Close)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#4 Violation : (dma50Close<=dma150Close)&&(dma50Close<=dma200Close).";
return cmtCandidate;
}
// Trend #4a check : The 50 day moving average must be greater than the 200 day moving average
if(dma50Close<=dma200Close)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#4a Violation : dma50Close<=dma200Close.";
return cmtCandidate;
}
// Trend #5 check : The current price must be greater than the 50 day moving average
if(currentPrice.Close<=dma50Close)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#5 Violation : currentPrice.Close<=dma50Close.";
return cmtCandidate;
}
// Trend #6 check. Evaluate the MinPercentReturnOver52WeekLow
double weekLow52=prices.Min(x => x.Close);
double latestClose=currentPrice.Close;
double percentReturnOver52WeekLow=((latestClose-weekLow52)/weekLow52)*100.00;
if(percentReturnOver52WeekLow<cmtParams.MinPercentReturnOver52WeekLow)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason=String.Format("Trend#6 Violation : percentReturnOver52WeekLow<={0}.",cmtParams.MinPercentReturnOver52WeekLow);
return cmtCandidate;
}
// Trend #7 check. Evaluate the MinPercentReturnProximityTo52WeekHigh
double weekHigh52=prices.Max(x => x.Close);
double percentReturnProximityTo52WeekHigh=double.NaN;
if(latestClose<weekHigh52) percentReturnProximityTo52WeekHigh=((weekHigh52-latestClose)/latestClose)*100.00;
else percentReturnProximityTo52WeekHigh=((latestClose-weekHigh52)/weekHigh52)*100.00;
if(latestClose<weekHigh52&&percentReturnProximityTo52WeekHigh>cmtParams.MinPercentReturnProximityTo52WeekHigh)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason=String.Format("Trend#7 Violation :PercentReturnProximityTo52WeekHigh<{0}.",cmtParams.MinPercentReturnProximityTo52WeekHigh);
return cmtCandidate;
}
// Trend #8 check. Evaluate the RSI
// generate a 14 day standard RSI with 30 days of pricing data
RSICollection rsiCollection=RSIGenerator.GenerateRSI(symbol,currentPrice.Date,30);
if(null==rsiCollection||0==rsiCollection.Count||rsiCollection[rsiCollection.Count-1].RSI<cmtParams.MinRSI)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason=String.Format("Trend#8 Violation : rsiCollection[rsiCollection.Count-1].RSI<{0}.",cmtParams.MinRSI);
return cmtCandidate;
}
// 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)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason=String.Format("Trend#3a Violation : Insufficient data to calulate DMA(200). Requires {0} days of DMA(200)",cmtParams.DMA200Horizon);
return cmtCandidate;
}
foreach(DateTime date in historicalDates)
{
Prices historicalPrices=GBPriceCache.GetInstance().GetPrices(symbol,date,MovingAverageGenerator.DayCount200);
if(null==historicalPrices||historicalPrices.Count<MovingAverageGenerator.DayCount200) continue;
dma200Prices=MovingAverageGenerator.GenerateMovingAverage(historicalPrices,MovingAverageGenerator.DayCount200);
dma200List.Insert(0,dma200Prices[0].AVGPrice); // The lowest index should wind up with most historical price. This way we calculate the proper slope
}
double[] averages=dma200List.ToArray();
double slope=Numerics.Slope(ref averages);
if(slope<=0)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason=String.Format("Trend#3 Violation : Slope of {0} days of 200DMA >0.",cmtParams.DMA200Horizon);
return cmtCandidate;
}
// Trend check ensure that prices are trending higher
if(cmtParams.UsePriceSlopeIndicator)
{
int dayCount=cmtParams.UsePriceSlopeIndicatorDays;
Prices pricesTrend=GBPriceCache.GetInstance().GetPrices(symbol,tradeDate,dayCount);
double[] pricesLow=Numerics.ToDouble(pricesTrend.GetPricesLow());
LeastSquaresResult lsr=LeastSquaresHelper.CalculateLeastSquares(pricesLow);
if(lsr.Slope<=0.00)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Price trend violation {0}. The {1} pricing slope is {2}",symbol,dayCount,Utility.FormatNumber(lsr.Slope,6));
return cmtCandidate;
}
}
// Filter penny stocks - don't trade anything less than $1.00
if(currentPrice.Close<1.00||currentPrice.Open<1.00)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Penny stock violation {0} Close price is {1}, Open price is ",symbol,Utility.FormatCurrency(currentPrice.Close),Utility.FormatCurrency(currentPrice.Open));
return cmtCandidate;
}
// Capture latest Volume - we'll do a min check later on
cmtCandidate.Volume=currentPrice.Volume;
// Daily Return Check
float[] dailyReturns=prices.GetReturns(); // First we build the returns (before we reverse the pricing direction)
if(HasReturnViolation(dailyReturns,cmtParams.DailyReturnLimit)) // Check the return stream. If any daily return exceeds DailyReturnLimit then we discard.
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Daily return violation for {0}. A daily return exceeded {1}%.",symbol,cmtParams.DailyReturnLimit);
return cmtCandidate;
}
// check for outliers in the return stream
if((from float value in dailyReturns where Math.Abs(value)>cmtParams.DailyReturnLimit select value).Count()>0)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Outlier encountered in return stream for {0}. Limit {1}",symbol,cmtParams.DailyReturnLimit);
return cmtCandidate;
}
// EBITDA screen
bool UseEBITDAScreen=true;
if(UseEBITDAScreen&&(double.IsNaN(fundamental.EBITDA)||fundamental.EBITDA<=0))
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#14 Violation : EBITDA";
return cmtCandidate;
}
bool UsePEScreen=true;
if(UsePEScreen&&(double.IsNaN(fundamental.PE))||fundamental.PE<=0.00)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#14 Violation : UsePEScreen";
return cmtCandidate;
}
// Setup for next tests
double profitMarginSlope=double.NaN;
DateTime minDate=DateTime.MinValue;
DateTime maxDate=DateTime.MinValue;
float[] values;
// Revenue per share screen
bool UseRevenuePerShareScreen=true;
if(UseRevenuePerShareScreen&&(double.IsNaN(fundamental.RevenuePerShare)||fundamental.RevenuePerShare<0.00))
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#14 Violation : Revenue Per Share";
return cmtCandidate;
}
// Trend#9 - My check Increasing EPS
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;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#9 Violation : No EPS time series to perform check.";
return cmtCandidate;
}
epsTimeSeries=new TimeSeriesCollection(epsTimeSeries.Take(3).ToList());
minDate=epsTimeSeries.Min(x => x.AsOf);
maxDate=epsTimeSeries.Max(x => x.AsOf);
values=epsTimeSeries.ToFloat();
values=Numerics.Reverse(ref values);
epsSlope=Numerics.Slope(values);
if(epsSlope<=0)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#9 Violation : epsSlope<=0.";
return cmtCandidate;
}
}
// 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;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#10 Violation : No Profit Margin series to perform check.";
return cmtCandidate;
}
profitMarginTimeSeries=new TimeSeriesCollection(profitMarginTimeSeries.Take(3).ToList());
minDate=profitMarginTimeSeries.Min(x => x.AsOf);
maxDate=profitMarginTimeSeries.Max(x => x.AsOf);
values=profitMarginTimeSeries.ToFloat();
values=Numerics.Reverse(ref values);
profitMarginSlope=Numerics.Slope(values);
if(profitMarginSlope<=0)
{
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason="Trend#10 Violation : profitMarginSlope<=0.";
return cmtCandidate;
}
}
// Calculate the Score
prices.Reverse(); // Reverse the series here.
double[] logPrices=null;
logPrices=new double[prices.Count];
for(int index=0;index<prices.Count;index++)
{
Price price=prices[index];
logPrices[index]=Math.Log(price.Close);
}
LeastSquaresResultWithR2 leastSquaresResult=LeastSquaresHelper.CalculateLeastSquaresWithR2(logPrices);
cmtCandidate=new CMTCandidate();
cmtCandidate.EPSSlope=epsSlope;
cmtCandidate.PriceSlope=leastSquaresResult.Slope;
cmtCandidate.ProfitMarginSlope=profitMarginSlope;
cmtCandidate.Symbol=symbol;
cmtCandidate.AnalysisDate=tradeDate;
cmtCandidate.Slope=leastSquaresResult.Slope;
cmtCandidate.Volatility=volatility;
cmtCandidate.AnnualizedReturn=Math.Pow(Math.Exp(cmtCandidate.Slope),252); //cmCandidate.AnnualizedReturn=Math.Pow(1.00+cmCandidate.Slope,252);
if(cmtCandidate.Slope<0) cmtCandidate.AnnualizedReturn*=-1.00; // preserve the sign of the slope
cmtCandidate.Score=leastSquaresResult.RSquared*cmtCandidate.AnnualizedReturn; // The greater the score the higher the rank
cmtCandidate.RSquared=leastSquaresResult.RSquared;
cmtCandidate.Beta=BetaGenerator.Beta(symbol,tradeDate,cmtParams.BetaMonths);
cmtCandidate.BetaMonths=cmtParams.BetaMonths;
if(double.IsNaN(cmtCandidate.Beta))
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Unable to calculate {0} month beta for {1} ",cmtParams.BetaMonths,symbol);
return cmtCandidate;
}
if(cmtCandidate.Beta<=0.00)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Beta for {0} is less than or equal to zero {1}",symbol,cmtCandidate.Beta);
return cmtCandidate;
}
if(cmtParams.UseMaxBeta&&cmtCandidate.Beta>cmtParams.MaxBeta)
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Beta for {0} exceeds maximum allowed. Candidate beta {1}, Max Beta:{2}",symbol,cmtCandidate.Beta,cmtParams.MaxBeta);
return cmtCandidate;
}
cmtCandidate.SharpeRatio=SharpeRatioGenerator.GenerateSharpeRatio(cmtCandidate.Symbol,tradeDate);
if(double.IsNaN(cmtCandidate.SharpeRatio))
{
cmtCandidate.Violation=true;
cmtCandidate.Reason=String.Format("Unable to calculate Sharpe Ratio for {0}",symbol);
return cmtCandidate;
}
return cmtCandidate;
}
catch(Exception exception)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Exception:{0}",exception.ToString()));
cmtCandidate.Violation=true;
cmtCandidate.Symbol=symbol;
cmtCandidate.Reason=exception.ToString();
return cmtCandidate;
}
}
private static bool HasReturnViolation(float[] dailyReturns,double dailyReturnLimit)
{
foreach(float dailyReturn in dailyReturns) if(Math.Abs(dailyReturn)>dailyReturnLimit) return true;
return false;
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.CMTrend
{
public class CMTGeneratorResult
{
public CMTGeneratorResult()
{
Success=false;
CMTCandidates=new CMTCandidates();
CMTCandidatesWithViolation=new CMTCandidates();
Messages=new List<String>();
}
public CMTCandidates CMTCandidates { get; set; }
public CMTCandidates CMTCandidatesWithViolation { get; set; }
public bool Success { get; set; }
public List<String> Messages { get; set; }
public String LastMessage { get { if(null==Messages||0==Messages.Count) return ""; else return Messages[0]; } }
}
}

View File

@@ -0,0 +1,31 @@
using MarketData.Cache;
using MarketData.MarketDataModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.CMTrend
{
public class CMTMACDIndicator
{
private CMTMACDIndicator()
{
}
public static bool IsMACDDowntrend(DateTime tradeDate,String symbol,CMTParams parameters)
{
Prices prices=GBPriceCache.GetInstance().GetPrices(symbol,tradeDate,parameters.MACDSignalDays*3);
if(null==prices||!prices[0].Date.Date.Equals(tradeDate.Date)) return true;
MACDSetup macdSetup=new MACDSetup(parameters.MACDSetup);
MACDSignals macdSignals=MACDGenerator.GenerateMACD(prices,macdSetup);
Signals signalsMACD=SignalGenerator.GenerateSignals(macdSignals);
signalsMACD=new Signals(signalsMACD.Take(parameters.MACDSignalDays).ToList());
int weakSellSignalCount=(from Signal signal in signalsMACD where signal.IsWeakSell() select signal).Count();
int strongSellSignalCount=(from Signal signal in signalsMACD where signal.IsStrongSell() select signal).Count();
if(parameters.MACDRejectWeakSells&&weakSellSignalCount>0) return true;
if(parameters.MACDRejectStrongSells&&strongSellSignalCount>0) return true;
return false;
}
}
}

View File

@@ -0,0 +1,376 @@
using MarketData.Utils;
using System;
using System.Collections.Generic;
namespace MarketData.Generator.CMTrend
{
public class CMTParams
{
public CMTParams()
{
SuspendTrading=false; // If this flag is set to true then no new positions will be opned.
UsePriceSlopeIndicator=true; // If this flag is set to true then enforce positive slope on prices over UserPriceSlopeIndicatorDays
UsePriceSlopeIndicatorDays=252; // The number of pricing days to use for the slope.
BetaMonths=6; // The number of months to use for Beta
AnalysisDate=DateTime.Now.Date; // The analysis date of the run
MarketCapLowerLimit=500000000; // MarketCap lower limit 50,0000,000
TradeDate=DateTime.Now; // The current trade date
SidewaysDetection=false; // Detect stock that are going nowhere. If we've held the stock for SidewaysAfterDays AND we've never adjusted the stop AND we can break even THEN we sell.
SidewaysAfterDays=30; // Sideways detection days.
MaxDailyPositions=3; // This is the maximum number of positions to pick up per analysis date. The default is 3
MaxOpenPositions=3; // This is the maximum number of open positions. I have tested this with 3 and had good results.
NoTradeSymbols="CLCT,PRSC,CMD,STAY,GBTC,YOKU,PNY,RFMD,ASAZY,USMO,VNR,STB,XIV,SYNT"; // ASAZY came up as candidate during 3/30 run but not available on Robinhood
OnlyTradeSymbols=""; // This should be a comma separated list of symbols which would serve as the universe of symbols to trade. If null or empty then we trade everything in security master
InitialCash=10000; // The initial cash
TotalRiskPercentDecimal=.05; // Total Risk of Initial Cash. The default is .02. I've been testing with .05
PositionRiskPercentDecimal=.12; // Risk per position - This will determine where the stop is placed. The default is .12
CheckOutliersInReturnStream=true; // If enabled then we check the return and ensure that no daily return exceeds DailyReturnLimit
DailyReturnLimit=.25; // If any single day return in the price stream exceeds this amount we toss it out. The default is .25
MinRSI=70; // The minimum RSI in order to consider the candidate. Default is 70
MinDaysBetweenReholding=30; // After selling a security we must wait this number of days before acting on a new buy signal . The default is 15
EquityOnly=false; // If set to true then ETFs are excluded
MinPercentReturnProximityTo52WeekHigh=30; // The minimum acceptable percent proximity to the 52 week high. The default is within 30 percent (i.e.) current price can be below the 52 week high by this margin. The larger the number , the wider the margin
MinPercentReturnOver52WeekLow=80; // The minimum acceptable percent return over the 52 week low. Marc recommends 80,90,100,200,300
ProfitMarginCheck=true; // If TRUE then profit margin time series must be present and slope must be increasing
EPSCheck=true; // If TRUE then eps time series must be present and slope must be increasing
LiquidityCheck=true; // If TRUE then the price history is checked against MinVolume
MinVolume=1000; // The minimum day volume in order to consider a security. This is used if LiquidityCheck is TRUE. Default is 5000
DMA200Horizon=15; // Number of days to examine when evaluating the slope of 200 day moving averages. Default is 20 days of DMA200's
MinDaysBetweenStopAdjustments=30; // We won't adjust a stop if the number of days between previous adjustment is less than this. Default is 60
MinDaysBetweenInitialStopAdjustment=5; // We won't change the initial stop until this number of days has elapsed. Default is 60.
MaxPricingExceptions=3; // This is the pricing exception limit. If we have this many of exceptions then we will sell the security at the last known good price.
UseMarketIndicator=true; // If true then we gauge the market based upon the benchmark's moving average
Benchmark="SPY"; // This is the benchmark security
BenchmarkMovingAverageDays=200; // If the latest benchmark Close is below DMA(BenchmarkMovingAverageDays) then we do not purchase new securities. I tested this with 200 and then with 55. 55 was 56% better over the period tested which was 01/06/2019-05/07/2021. so I am setting this to 100.. just because.
BenchmarkMovingAverageHorizon=5; // This is the horizon for the benchmark indicator. it must be trading above BenchmarkMovingAverageDays for BenchmarkMovingAverageHorizon days
UseMarketIndicatorVolatility=true; // If this is true then we detect volatile market by examing lower L band breaks on the ~VIX
UseMarketIndicatorVolatilityHorizon=60; // The horizon over which to examine lower L band breaks in ~VIX
UseMarketIndicatorVolatilityBenchmark="^VIX"; // The benchmark to use for volatility
UseStopLimitScaling=true; // When set to true this will scale (tighten) the stop limit as time progresses based upon an anticipated holding period of StopLimitScalingDays.
StopLimitScalingType="AverageTrueRange"; // Acceptable types are "AverageTrueRange".
StopLimitScalingVolatilityDays=30; // StopLimitScalingVolatilityDays=5 The StopLimitScaling takes volatility into account. This parameter specifies how many days of pricing to use for the volatility calculation.
EvaluateStopOnUpTrend=false; // If set to true then the stop limit is only evaluated if prices are trending up.
SellOnDMABreak=true; // If true then we look lok for breaks of all DMAs listed under DMABreak
DMABreakValues="200"; // The defaut value is 200. This can be a comma separated list. For instance 50,100,200
DMABreakForceBreak=false; // If this flag is set to true then we will sell a security on DMA break even if it means taking a loss on the position.
EntryType="OverExtended,MVP,PriceTrend,VolumeTrend"; // The entry type indictor. NarrowRange, Swing, MACD, PriceTRend, VolumeTrend, ChannelBreakout. Default is "MVP,NarrowRange,MACD,PriceTrend,VolumeTrend".
PriceTrendDays=20; // If PriceTrend is in the EntryType list then We want to see a series of higher highs and higher lows. This is the horizon for those observations. Default is 10.
EntryHorizon=30; // For the NarrowRange entry indicator this is the number of days to consider
MACDSetup="(12,26,9)"; // setup for MACD Entry. Default is (12,26,9)
MACDSignalDays=5; // Number of signal days to consider. Default is 12
MACDRejectStrongSells=true; // MACD reject. Default is false. **Used only if MACD is in the EntryType list
MACDRejectWeakSells=true; // MACD reject. Default is true. **Used only if MACD is in the EntryType list
VolumeTrendDays=10; // Volume trend can be used as an entry indicator. The default value is 10 days of increasing volume
CandidateExpiryDays=180; // Candidates will be kept in the candidate pool for entry search for this many days after which they will be removed and no longer available for consideration
ChannelBreakoutHorizon=40; // Horizon for ChannelBreakout entry
UseOverExtendedIndicatorDays=45; // 10 This is the number of days of history to scan for OverExtension detetction. 10 gives best results in backtest
UseOverExtendedIndicatorViolationThreshhold=1; // This is the number of items that constitute an upper band break. (i.e.) if this is set to 1 then a single band break is a violation... if 2 then >=2 band breaks are a violation etc., 1.00 gives the best results in backtest
UseOverExtendedIndicatorMarginPercent=1; // Add this in so we can control the margin. The best value is 1.00 from backtest results
MaxBeta=10.00; // Candidates with Beta that exceed this are rejected.
UseMaxBeta=false; // Utilize the MaxBeta filter
UseProfitMaximization=true; // Maximize profits when setting stop limits. What this does is to instead of using 3*ATR(20) it will use UseProfitMaximizationATRMultiplier*ATR(20) to set the stop limit for R's greater than or equal to UseProfitMaximizationRs
UseProfitMaximizationExpression="R_THRESSHOLD=4;MAX_ATR=3;MULTIPLIER=MAX_ATR;IF(RMultiple>=R_THRESSHOLD){MULTIPLIER=1.2;}"; // The default ATR multiplier is 3 which will maintain a wider gap. 1.2 will follow more closely
UseTradeOnlySectors=false; // If set to true then only consider companies in specified sectors
UseTradeOnlySectorsSectors="Healthcare,Technology,Basic Materials,Consumer Defensive,Industrials";
}
public bool SuspendTrading{get;set;}
public bool UsePriceSlopeIndicator{get;set;}
public int UsePriceSlopeIndicatorDays{get;set;}
public bool UseMarketIndicatorVolatility{get;set;}
public int UseMarketIndicatorVolatilityHorizon{get;set;}
public string UseMarketIndicatorVolatilityBenchmark{get;set;}
public int BetaMonths { get; set; }
public DateTime AnalysisDate { get; set; }
public DateTime TradeDate { get; set; }
public double MarketCapLowerLimit { get; set; }
public bool SidewaysDetection { get; set; }
public int SidewaysAfterDays { get; set; }
public int PriceTrendDays { get; set; }
public bool CheckOutliersInReturnStream { get; set; }
public double DailyReturnLimit { get; set; }
public int MaxDailyPositions { get; set; }
public int MaxOpenPositions { get; set; }
public String NoTradeSymbols { get; set; }
public String OnlyTradeSymbols { get; set; }
public double MinRSI { get; set; }
public List<String> NoTradeSymbolsList { get { return null==NoTradeSymbols?null:Utility.ToList(NoTradeSymbols); } }
public List<String> OnlyTradeSymbolsList { get { return null==OnlyTradeSymbols?null:Utility.ToList(OnlyTradeSymbols); } }
public double InitialCash { get; set; }
public double TotalRiskPercentDecimal { get; set; }
public double PositionRiskPercentDecimal { get; set; }
public bool EquityOnly { get; set; }
public double MinPercentReturnProximityTo52WeekHigh { get; set; }
public double MinPercentReturnOver52WeekLow { get; set; }
public bool ProfitMarginCheck { get; set; }
public bool EPSCheck { get; set; }
public int MinDaysBetweenReholding { get; set; }
public bool LiquidityCheck { get; set; }
public int MinVolume { get; set; }
public int DMA200Horizon { get; set; }
public int MinDaysBetweenStopAdjustments { get; set; }
public int MinDaysBetweenInitialStopAdjustment { get; set; }
public int MaxPricingExceptions { get; set; }
public String MACDSetup { get; set; }
public int MACDSignalDays { get; set; }
public bool MACDRejectStrongSells { get; set; }
public bool MACDRejectWeakSells { get; set; }
public bool UseMarketIndicator { get; set; }
public String Benchmark { get; set; }
public int BenchmarkMovingAverageDays { get; set; }
public int BenchmarkMovingAverageHorizon { get; set; }
public bool UseStopLimitScaling { get; set; }
public String StopLimitScalingType { get; set; }
public int StopLimitScalingVolatilityDays { get; set; }
public bool SellOnDMABreak { get; set; }
public String DMABreakValues { get; set; }
public bool DMABreakForceBreak { get; set; }
public List<String> DMABreakValuesCollection { get { return (!SellOnDMABreak)||(null==DMABreakValues)?new List<String>():Utility.ToList(DMABreakValues); } }
public String EntryType { get; set; }
public List<String> EntryTypesCollection { get { return null==EntryType?new List<String>():Utility.ToList(EntryType); } }
public int EntryHorizon { get; set; }
public int CandidateExpiryDays { get; set; }
public int VolumeTrendDays { get; set; }
public int ChannelBreakoutHorizon { get; set; }
public int UseOverExtendedIndicatorDays { get; set; }
public int UseOverExtendedIndicatorViolationThreshhold { get; set; }
public double UseOverExtendedIndicatorMarginPercent { get; set; }
public bool UseMaxBeta { get; set; }
public double MaxBeta { get; set; }
public bool UseProfitMaximization{get;set;}
public string UseProfitMaximizationExpression{get;set;}
public bool UseTradeOnlySectors{get;set;}
public String UseTradeOnlySectorsSectors{get;set;}
public bool EvaluateStopOnUpTrend { get; set; }
public void DisplayHeader()
{
MDTrace.WriteLine(LogLevel.DEBUG,"Setting,Value");
}
public NVPCollection ToNVPCollection()
{
NVPCollection nvpCollection=new NVPCollection();
nvpCollection.Add(new NVP("SuspendTrading",SuspendTrading.ToString()));
nvpCollection.Add(new NVP("UsePriceSlopeIndicator",UsePriceSlopeIndicator.ToString()));
nvpCollection.Add(new NVP("UsePriceSlopeIndicatorDays",UsePriceSlopeIndicatorDays.ToString()));
nvpCollection.Add(new NVP("AnalysisDate",AnalysisDate.ToShortDateString()));
nvpCollection.Add(new NVP("BetaMonths",BetaMonths.ToString()));
nvpCollection.Add(new NVP("TradeDate",TradeDate.ToShortDateString()));
nvpCollection.Add(new NVP("MarketCapLowerLimit",MarketCapLowerLimit.ToString()));
nvpCollection.Add(new NVP("SidewaysDetection",SidewaysDetection.ToString()));
nvpCollection.Add(new NVP("SidewaysAfterDays",SidewaysAfterDays.ToString()));
nvpCollection.Add(new NVP("PriceTrendDays",PriceTrendDays.ToString()));
nvpCollection.Add(new NVP("CheckOutliersInReturnStream",CheckOutliersInReturnStream.ToString()));
nvpCollection.Add(new NVP("DailyReturnLimit",DailyReturnLimit.ToString()));
nvpCollection.Add(new NVP("MaxDailyPositions",MaxDailyPositions.ToString()));
nvpCollection.Add(new NVP("MaxOpenPositions",MaxOpenPositions.ToString()));
nvpCollection.Add(new NVP("NoTradeSymbols",NoTradeSymbols.ToString()));
nvpCollection.Add(new NVP("OnlyTradeSymbols",OnlyTradeSymbols.ToString()));
nvpCollection.Add(new NVP("MinRSI",MinRSI.ToString()));
nvpCollection.Add(new NVP("InitialCash",InitialCash.ToString()));
nvpCollection.Add(new NVP("TotalRiskPercentDecimal",TotalRiskPercentDecimal.ToString()));
nvpCollection.Add(new NVP("PositionRiskPercentDecimal",PositionRiskPercentDecimal.ToString()));
nvpCollection.Add(new NVP("EquityOnly",EquityOnly.ToString()));
nvpCollection.Add(new NVP("MinPercentReturnProximityTo52WeekHigh",MinPercentReturnProximityTo52WeekHigh.ToString()));
nvpCollection.Add(new NVP("MinPercentReturnOver52WeekLow",MinPercentReturnOver52WeekLow.ToString()));
nvpCollection.Add(new NVP("ProfitMarginCheck",ProfitMarginCheck.ToString()));
nvpCollection.Add(new NVP("EPSCheck",EPSCheck.ToString()));
nvpCollection.Add(new NVP("MinDaysBetweenReholding",MinDaysBetweenReholding.ToString()));
nvpCollection.Add(new NVP("LiquidityCheck",LiquidityCheck.ToString()));
nvpCollection.Add(new NVP("MinVolume",MinVolume.ToString()));
nvpCollection.Add(new NVP("DMA200Horizon",DMA200Horizon.ToString()));
nvpCollection.Add(new NVP("MinDaysBetweenStopAdjustments",MinDaysBetweenStopAdjustments.ToString()));
nvpCollection.Add(new NVP("MinDaysBetweenInitialStopAdjustment",MinDaysBetweenInitialStopAdjustment.ToString()));
nvpCollection.Add(new NVP("MaxPricingExceptions",MaxPricingExceptions.ToString()));
nvpCollection.Add(new NVP("MACDSetup",MACDSetup.ToString()));
nvpCollection.Add(new NVP("MACDSignalDays",MACDSignalDays.ToString()));
nvpCollection.Add(new NVP("MACDRejectStrongSells",MACDRejectStrongSells.ToString()));
nvpCollection.Add(new NVP("MACDRejectWeakSells",MACDRejectWeakSells.ToString()));
nvpCollection.Add(new NVP("UseMarketIndicator",UseMarketIndicator.ToString()));
nvpCollection.Add(new NVP("Benchmark",Benchmark.ToString()));
nvpCollection.Add(new NVP("BenchmarkMovingAverageDays",BenchmarkMovingAverageDays.ToString()));
nvpCollection.Add(new NVP("BenchmarkMovingAverageHorizon",BenchmarkMovingAverageHorizon.ToString()));
nvpCollection.Add(new NVP("UseMarketIndicatorVolatility",UseMarketIndicatorVolatility.ToString()));
nvpCollection.Add(new NVP("UseMarketIndicatorVolatilityHorizon",UseMarketIndicatorVolatilityHorizon.ToString()));
nvpCollection.Add(new NVP("UseMarketIndicatorVolatilityBenchmark",UseMarketIndicatorVolatilityBenchmark.ToString()));
nvpCollection.Add(new NVP("UseStopLimitScaling",UseStopLimitScaling.ToString()));
nvpCollection.Add(new NVP("StopLimitScalingType",StopLimitScalingType.ToString()));
nvpCollection.Add(new NVP("StopLimitScalingVolatilityDays",StopLimitScalingVolatilityDays.ToString()));
nvpCollection.Add(new NVP("SellOnDMABreak",SellOnDMABreak.ToString()));
nvpCollection.Add(new NVP("DMABreakValues",DMABreakValues.ToString()));
nvpCollection.Add(new NVP("DMABreakForceBreak",DMABreakForceBreak.ToString()));
nvpCollection.Add(new NVP("EntryType",EntryType.ToString()));
nvpCollection.Add(new NVP("EntryHorizon",EntryHorizon.ToString()));
nvpCollection.Add(new NVP("CandidateExpiryDays",CandidateExpiryDays.ToString()));
nvpCollection.Add(new NVP("VolumeTrendDays",VolumeTrendDays.ToString()));
nvpCollection.Add(new NVP("ChannelBreakoutHorizon",ChannelBreakoutHorizon.ToString()));
nvpCollection.Add(new NVP("UseOverExtendedIndicatorDays",UseOverExtendedIndicatorDays.ToString()));
nvpCollection.Add(new NVP("UseOverExtendedIndicatorViolationThreshhold",UseOverExtendedIndicatorViolationThreshhold.ToString()));
nvpCollection.Add(new NVP("UseOverExtendedIndicatorMarginPercent",UseOverExtendedIndicatorMarginPercent.ToString()));
nvpCollection.Add(new NVP("MaxBeta",MaxBeta.ToString()));
nvpCollection.Add(new NVP("UseMaxBeta",UseMaxBeta.ToString()));
nvpCollection.Add(new NVP("UseProfitMaximization",UseProfitMaximization.ToString()));
nvpCollection.Add(new NVP("UseProfitMaximizationExpression",UseProfitMaximizationExpression.ToString()));
nvpCollection.Add(new NVP("UseTradeOnlySectors",UseTradeOnlySectors.ToString()));
nvpCollection.Add(new NVP("UseTradeOnlySectorsSectors",UseTradeOnlySectorsSectors.ToString()));
nvpCollection.Add(new NVP("EvaluateStopOnUpTrend",EvaluateStopOnUpTrend.ToString()));
return nvpCollection;
}
public static CMTParams FromNVPCollection(NVPCollection nvpCollection)
{
CMTParams cmtParams=new CMTParams();
NVPDictionary nvpDictionary=nvpCollection.ToDictionary();
if(nvpDictionary.ContainsKey("SuspendTrading"))
{
cmtParams.SuspendTrading=nvpDictionary["SuspendTrading"].Get<bool>();
}
if(nvpDictionary.ContainsKey("UsePriceSlopeIndicator"))
{
cmtParams.UsePriceSlopeIndicator=nvpDictionary["UsePriceSlopeIndicator"].Get<bool>();
cmtParams.UsePriceSlopeIndicatorDays=nvpDictionary["UsePriceSlopeIndicatorDays"].Get<int>();
}
if(nvpDictionary.ContainsKey("UseMarketIndicatorVolatility"))
{
cmtParams.UseMarketIndicatorVolatility=nvpDictionary["UseMarketIndicatorVolatility"].Get<bool>();
cmtParams.UseMarketIndicatorVolatilityHorizon=nvpDictionary["UseMarketIndicatorVolatilityHorizon"].Get<int>();
cmtParams.UseMarketIndicatorVolatilityBenchmark=nvpDictionary["UseMarketIndicatorVolatilityBenchmark"].Get<String>();
}
cmtParams.AnalysisDate=nvpDictionary["AnalysisDate"].Get<DateTime>();
cmtParams.BetaMonths=nvpDictionary["BetaMonths"].Get<int>();
cmtParams.TradeDate=nvpDictionary["TradeDate"].Get<DateTime>();
cmtParams.MarketCapLowerLimit=nvpDictionary["MarketCapLowerLimit"].Get<double>();
cmtParams.SidewaysDetection=nvpDictionary["SidewaysDetection"].Get<bool>();
cmtParams.SidewaysAfterDays=nvpDictionary["SidewaysAfterDays"].Get<int>();
cmtParams.PriceTrendDays=nvpDictionary["PriceTrendDays"].Get<int>();
cmtParams.CheckOutliersInReturnStream=nvpDictionary["CheckOutliersInReturnStream"].Get<bool>();
cmtParams.DailyReturnLimit=nvpDictionary["DailyReturnLimit"].Get<double>();
cmtParams.MaxDailyPositions=nvpDictionary["MaxDailyPositions"].Get<int>();
cmtParams.MaxOpenPositions=nvpDictionary["MaxOpenPositions"].Get<int>();
cmtParams.NoTradeSymbols=nvpDictionary["NoTradeSymbols"].Get<String>();
if(nvpDictionary.ContainsKey("OnlyTradeSymbols")) cmtParams.OnlyTradeSymbols=nvpDictionary["OnlyTradeSymbols"].Get<String>();
cmtParams.MinRSI=nvpDictionary["MinRSI"].Get<double>();
cmtParams.InitialCash=nvpDictionary["InitialCash"].Get<Double>();
cmtParams.TotalRiskPercentDecimal=nvpDictionary["TotalRiskPercentDecimal"].Get<double>();
cmtParams.PositionRiskPercentDecimal=nvpDictionary["PositionRiskPercentDecimal"].Get<double>();
cmtParams.EquityOnly=nvpDictionary["EquityOnly"].Get<bool>();
cmtParams.MinPercentReturnProximityTo52WeekHigh=nvpDictionary["MinPercentReturnProximityTo52WeekHigh"].Get<double>();
cmtParams.MinPercentReturnOver52WeekLow=nvpDictionary["MinPercentReturnOver52WeekLow"].Get<double>();
cmtParams.ProfitMarginCheck=nvpDictionary["ProfitMarginCheck"].Get<bool>();
cmtParams.EPSCheck=nvpDictionary["EPSCheck"].Get<bool>();
cmtParams.MinDaysBetweenReholding=nvpDictionary["MinDaysBetweenReholding"].Get<int>();
cmtParams.LiquidityCheck=nvpDictionary["LiquidityCheck"].Get<bool>();
cmtParams.MinVolume=nvpDictionary["MinVolume"].Get<int>();
cmtParams.DMA200Horizon=nvpDictionary["DMA200Horizon"].Get<int>();
cmtParams.MinDaysBetweenStopAdjustments=nvpDictionary["MinDaysBetweenStopAdjustments"].Get<int>();
cmtParams.MinDaysBetweenInitialStopAdjustment=nvpDictionary["MinDaysBetweenInitialStopAdjustment"].Get<int>();
cmtParams.MaxPricingExceptions=nvpDictionary["MaxPricingExceptions"].Get<int>();
cmtParams.MACDSetup=nvpDictionary["MACDSetup"].Get<String>();
cmtParams.MACDSignalDays=nvpDictionary["MACDSignalDays"].Get<int>();
cmtParams.MACDRejectStrongSells=nvpDictionary["MACDRejectStrongSells"].Get<bool>();
cmtParams.MACDRejectWeakSells=nvpDictionary["MACDRejectWeakSells"].Get<bool>();
cmtParams.UseMarketIndicator=nvpDictionary["UseMarketIndicator"].Get<bool>();
cmtParams.Benchmark=nvpDictionary["Benchmark"].Get<String>();
cmtParams.BenchmarkMovingAverageDays=nvpDictionary["BenchmarkMovingAverageDays"].Get<int>();
cmtParams.BenchmarkMovingAverageHorizon=nvpDictionary["BenchmarkMovingAverageHorizon"].Get<int>();
cmtParams.UseStopLimitScaling=nvpDictionary["UseStopLimitScaling"].Get<bool>();
if(nvpDictionary.ContainsKey("StopLimitScalingType")) cmtParams.StopLimitScalingType=nvpDictionary["StopLimitScalingType"].Get<String>();
cmtParams.StopLimitScalingVolatilityDays=nvpDictionary["StopLimitScalingVolatilityDays"].Get<int>();
cmtParams.SellOnDMABreak=nvpDictionary["SellOnDMABreak"].Get<bool>();
cmtParams.DMABreakValues=nvpDictionary["DMABreakValues"].Get<String>();
if(nvpDictionary.ContainsKey("DMABreakForceBreak")) cmtParams.DMABreakForceBreak=nvpDictionary["DMABreakForceBreak"].Get<bool>();
cmtParams.EntryType=nvpDictionary["EntryType"].Get<String>();
cmtParams.EntryHorizon=nvpDictionary["EntryHorizon"].Get<int>();
cmtParams.CandidateExpiryDays=nvpDictionary["CandidateExpiryDays"].Get<int>();
if(nvpDictionary.ContainsKey("VolumeTrendDays")) cmtParams.VolumeTrendDays=nvpDictionary["VolumeTrendDays"].Get<int>();
if(nvpDictionary.ContainsKey("ChannelBreakoutHorizon")) cmtParams.ChannelBreakoutHorizon=nvpDictionary["ChannelBreakoutHorizon"].Get<int>();
cmtParams.UseOverExtendedIndicatorDays=nvpDictionary["UseOverExtendedIndicatorDays"].Get<int>();
cmtParams.UseOverExtendedIndicatorViolationThreshhold=nvpDictionary["UseOverExtendedIndicatorViolationThreshhold"].Get<int>();
cmtParams.UseOverExtendedIndicatorMarginPercent=nvpDictionary["UseOverExtendedIndicatorMarginPercent"].Get<double>();
cmtParams.UseMaxBeta=nvpDictionary["UseMaxBeta"].Get<bool>();
cmtParams.MaxBeta=nvpDictionary["MaxBeta"].Get<double>();
if(nvpDictionary.ContainsKey("UseProfitMaximization"))
{
cmtParams.UseProfitMaximization=nvpDictionary["UseProfitMaximization"].Get<bool>();
cmtParams.UseProfitMaximizationExpression=nvpDictionary["UseProfitMaximizationExpression"].Get<String>();
}
if(nvpDictionary.ContainsKey("UseTradeOnlySectors"))
{
cmtParams.UseTradeOnlySectors=nvpDictionary["UseTradeOnlySectors"].Get<bool>();
cmtParams.UseTradeOnlySectorsSectors=nvpDictionary["UseTradeOnlySectorsSectors"].Get<String>();
}
if(nvpDictionary.ContainsKey("EvaluateStopOnUpTrend"))
{
cmtParams.EvaluateStopOnUpTrend=nvpDictionary["EvaluateStopOnUpTrend"].Get<bool>();
}
return cmtParams;
}
public void DisplayConfiguration()
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("SuspendTrading,{0}",SuspendTrading));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UsePriceSlopeIndicator,{0}",UsePriceSlopeIndicator));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UsePriceSlopeIndicatorDays,{0}",UsePriceSlopeIndicatorDays));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("AnalysisDate,{0}",AnalysisDate));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("TradeDate,{0}",TradeDate));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("SidewaysDetection,{0}",SidewaysDetection));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("SidewaysAfterDays,{0}",SidewaysAfterDays));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("PriceTrendDays,{0}",PriceTrendDays));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MaxDailyPositions,{0}",MaxDailyPositions));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MaxOpenPositions,{0}",MaxOpenPositions));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("NoTradeSymbols,{0}",NoTradeSymbols));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("OnlyTradeSymbols,{0}",OnlyTradeSymbols));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("InitialCash,{0}",InitialCash));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("TotalRiskPercentDecimal,{0}",TotalRiskPercentDecimal));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("PositionRiskPercentDecimal,{0}",PositionRiskPercentDecimal));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("CheckOutliersInReturnStream,{0}",CheckOutliersInReturnStream));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("DailyReturnLimit,{0}",DailyReturnLimit));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MinRSI,{0}",MinRSI));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MinDaysBetweenReholding,{0}",MinDaysBetweenReholding));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("EquityOnly,{0}",EquityOnly));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MinPercentReturnProximityTo52WeekHigh,{0}",MinPercentReturnProximityTo52WeekHigh));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MinPercentReturnOver52WeekLow,{0}",MinPercentReturnOver52WeekLow));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("ProfitMarginCheck,{0}",ProfitMarginCheck));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("EPSCheck,{0}",EPSCheck));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("LiquidityCheck,{0}",LiquidityCheck));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MinVolume,{0}",MinVolume));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("DMA200Horizon,{0}",DMA200Horizon));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MinDaysBetweenStopAdjustments,{0}",MinDaysBetweenStopAdjustments));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MinDaysBetweenInitialStopAdjustment,{0}",MinDaysBetweenInitialStopAdjustment));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MaxPricingExceptions,{0}",MaxPricingExceptions));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MACDSetup,{0}",MACDSetup));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MACDSignalDays,{0}",MACDSignalDays));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MACDRejectStrongSells,{0}",MACDRejectStrongSells));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MACDRejectWeakSells,{0}",MACDRejectWeakSells));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseMarketIndicator,{0}",UseMarketIndicator));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Benchmark,{0}",Benchmark));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("BenchmarkMovingAverageDays,{0}",BenchmarkMovingAverageDays));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("BenchmarkMovingAverageHorizon,{0}",BenchmarkMovingAverageHorizon));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseMarketIndicatorVolatility,{0}",UseMarketIndicatorVolatility));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseMarketIndicatorVolatilityHorizon,{0}",UseMarketIndicatorVolatilityHorizon));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseMarketIndicatorVolatilityBenchmark,{0}",UseMarketIndicatorVolatilityBenchmark));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseStopLimitScaling,{0}",UseStopLimitScaling));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("StopLimitScalingType,{0}",StopLimitScalingType));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("StopLimitScalingVolatilityDays,{0}",StopLimitScalingVolatilityDays));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("SellOnDMABreak,{0}",SellOnDMABreak));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("DMABreakValues,{0}",DMABreakValues));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("DMABreakForceBreak,{0}",DMABreakForceBreak));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("EntryType,{0}",EntryType));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("EntryHorizon,{0}",EntryHorizon));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("CandidateExpiryDays,{0}",CandidateExpiryDays));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("VolumeTrendDays,{0}",VolumeTrendDays));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("ChannelBreakoutHorizon,{0}",ChannelBreakoutHorizon));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseOverExtendedIndicatorDays,{0}",UseOverExtendedIndicatorDays.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseOverExtendedIndicatorViolationThreshhold,{0}",UseOverExtendedIndicatorViolationThreshhold.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseOverExtendedIndicatorMarginPercent,{0}",UseOverExtendedIndicatorMarginPercent.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseMaxBeta,{0}",UseMaxBeta.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MaxBeta,{0}",MaxBeta.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("MarketCapLowerLimit,{0}",MarketCapLowerLimit.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("BetaMonths,{0}",BetaMonths.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseProfitMaximization,{0}",UseProfitMaximization.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseProfitMaximizationExpression,{0}",UseProfitMaximizationExpression.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseTradeOnlySectors,{0}",UseTradeOnlySectors.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("UseTradeOnlySectorsSectors,{0}",UseTradeOnlySectorsSectors.ToString()));
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("EvaluateStopOnUpTrend,{0}",EvaluateStopOnUpTrend.ToString()));
}
}
}

View File

@@ -0,0 +1,310 @@
using System;
using System.Collections.Generic;
using MarketData.MarketDataModel;
using MarketData.Utils;
using System.Linq;
using MarketData.Generator.Interface;
namespace MarketData.Generator.CMTrend
{
public class Position : IPosition
{
public Position()
{
CurrentPrice=double.NaN;
}
public Position(Position position)
{
Symbol=position.Symbol;
PurchaseDate=position.PurchaseDate;
SellDate=position.SellDate;
Shares=position.Shares;
PurchasePrice=position.PurchasePrice;
CurrentPrice=position.CurrentPrice;
R=position.R;
C=position.C;
PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
InitialStopLimit=position.InitialStopLimit;
TrailingStopLimit=position.TrailingStopLimit;
Volume=position.Volume;
Volatility=position.Volatility;
LastStopAdjustment=position.LastStopAdjustment;
Comment=position.Comment;
}
public static Position Clone(Position position)
{
Position clonedPosition=new Position();
clonedPosition.Symbol=position.Symbol;
clonedPosition.PurchaseDate=position.PurchaseDate;
clonedPosition.SellDate=position.SellDate;
clonedPosition.Shares=position.Shares;
clonedPosition.PurchasePrice=position.PurchasePrice;
clonedPosition.CurrentPrice=position.CurrentPrice;
clonedPosition.R=position.R;
clonedPosition.C=position.C;
clonedPosition.PositionRiskPercentDecimal=position.PositionRiskPercentDecimal;
clonedPosition.InitialStopLimit=position.InitialStopLimit;
clonedPosition.TrailingStopLimit=position.TrailingStopLimit;
clonedPosition.Volume=position.Volume;
clonedPosition.Volatility=position.Volatility;
clonedPosition.LastStopAdjustment=position.LastStopAdjustment;
clonedPosition.Comment=position.Comment;
return clonedPosition;
}
public String Symbol { get; set; }
public DateTime PurchaseDate { get; set; }
public DateTime SellDate { get; set; }
public double Shares { get; set; } // This is actual shares (round down P to the nearest whole number)
public double PurchasePrice { get; set; }
public double CurrentPrice { get; set; } // When the position is sold the current price will hold the sell price
public double Exposure { get { return Shares*PurchasePrice; } } // Derived
public double MarketValue { get { return Shares*CurrentPrice; } } // Derived
public double GainLoss { get { return MarketValue-Exposure; } } // Derived
public double GetGainLoss(Price currentPrice) { return (Shares*currentPrice.Close)-Exposure; } // get the gain loss based upon the given price
public double GainLossPcnt { get { return (MarketValue-Exposure)/Exposure; } } // Derived
public double PositionRiskPercentDecimal { get; set; } // (i.e.) .06 = 6%
public double R { get; set; } // PositionRiskPercentDecimal*PurchasePrice
public double C { get; set; } // AvailableCash * TotalRiskPercentDecimal
public double P { get { return C/R; } } // Derived. This is the number of shares to buy according to risk limits
public double TrailingStopLimit { get; set; } // This is the trailing stop limit.
public double InitialStopLimit { get; set; } // This is the initial stop limit.
public DateTime LastStopAdjustment { get; set; }
public double TotalRiskExposure { get { return R*Shares; } } // This is the total risk in dollars that we are exposed to
public double RMultiple { get { return (CurrentPrice-PurchasePrice)/R; } } // Derived.
public String RMultipleAsString
{
get
{
return Utility.FormatNumber(RMultiple,2,false)+"R";
}
} // Derived.
public double Volatility { get; set; }
public long Volume { get; set; }
public String Comment { get; set; }
public virtual NVPCollection ToNVPCollection()
{
NVPCollection nvpCollection=new NVPCollection();
nvpCollection.Add(new NVP("Symbol",Symbol.ToString()));
nvpCollection.Add(new NVP("PurchaseDate",PurchaseDate.ToString()));
nvpCollection.Add(new NVP("SellDate",SellDate.ToString()));
nvpCollection.Add(new NVP("Shares",Shares.ToString()));
nvpCollection.Add(new NVP("PurchasePrice",PurchasePrice.ToString()));
if(!double.IsNaN(CurrentPrice)) nvpCollection.Add(new NVP("CurrentPrice",CurrentPrice.ToString()));
if(!double.IsNaN(Exposure)) nvpCollection.Add(new NVP("Exposure",Exposure.ToString()));
if(!double.IsNaN(MarketValue)) nvpCollection.Add(new NVP("MarketValue",MarketValue.ToString()));
if(!double.IsNaN(GainLoss)) nvpCollection.Add(new NVP("GainLoss",GainLoss.ToString()));
if(!double.IsNaN(GainLossPcnt)) nvpCollection.Add(new NVP("GainLossPcnt",GainLossPcnt.ToString()));
if(!double.IsNaN(PositionRiskPercentDecimal)) nvpCollection.Add(new NVP("PositionRiskDecimal",PositionRiskPercentDecimal.ToString()));
if(!double.IsNaN(R)) nvpCollection.Add(new NVP("R",R.ToString()));
if(!double.IsNaN(C)) nvpCollection.Add(new NVP("C",C.ToString()));
if(!double.IsNaN(C)) nvpCollection.Add(new NVP("P",P.ToString()));
if(!double.IsNaN(InitialStopLimit)) nvpCollection.Add(new NVP("InitialStopLimit",InitialStopLimit.ToString()));
if(!double.IsNaN(TrailingStopLimit)) nvpCollection.Add(new NVP("TrailingStopLimit",TrailingStopLimit.ToString()));
if(!double.IsNaN(TotalRiskExposure)) nvpCollection.Add(new NVP("TotalRiskExposure",TotalRiskExposure.ToString()));
if(!double.IsNaN(RMultiple)) nvpCollection.Add(new NVP("RMultiple",RMultipleAsString));
if(!double.IsNaN(Volatility)) nvpCollection.Add(new NVP("Volatility",Volatility.ToString()));
nvpCollection.Add(new NVP("Volume",Volume.ToString()));
nvpCollection.Add(new NVP("LastStopAdjustment",LastStopAdjustment.ToString()));
if(null!=Comment) nvpCollection.Add(new NVP("Comment",Comment));
return nvpCollection;
}
public static Position FromNVPCollection(NVPCollection nvpCollection)
{
Position position=new Position();
NVPDictionary nvpDictionary=nvpCollection.ToDictionary();
position.Symbol=nvpDictionary["Symbol"].Get<String>();
position.PurchaseDate=nvpDictionary["PurchaseDate"].Get<DateTime>();
position.SellDate=nvpDictionary["SellDate"].Get<DateTime>();
position.Shares=nvpDictionary["Shares"].Get<double>();
position.PurchasePrice=nvpDictionary["PurchasePrice"].Get<double>();
if(nvpDictionary.ContainsKey("CurrentPrice")) position.CurrentPrice=nvpDictionary["CurrentPrice"].Get<double>();
if(nvpDictionary.ContainsKey("R")) position.R=nvpDictionary["R"].Get<double>();
if(nvpDictionary.ContainsKey("C")) position.C=nvpDictionary["C"].Get<double>();
if(nvpDictionary.ContainsKey("PositionRiskDecimal")) position.PositionRiskPercentDecimal=nvpDictionary["PositionRiskDecimal"].Get<double>();
if(nvpDictionary.ContainsKey("InitialStopLimit")) position.InitialStopLimit=nvpDictionary["InitialStopLimit"].Get<double>();
if(nvpDictionary.ContainsKey("TrailingStopLimit")) position.TrailingStopLimit=nvpDictionary["TrailingStopLimit"].Get<double>();
if(nvpDictionary.ContainsKey("Volatility")) position.Volatility=nvpDictionary["Volatility"].Get<double>();
if(nvpDictionary.ContainsKey("Volume")) position.Volume=nvpDictionary["Volume"].Get<int>();
if(nvpDictionary.ContainsKey("LastStopAdjustment")) position.LastStopAdjustment=nvpDictionary["LastStopAdjustment"].Get<DateTime>();
if(nvpDictionary.ContainsKey("Comment")) position.Comment=nvpDictionary["Comment"].Get<String>();
return position;
}
public void Display()
{
if(Utility.IsEpoch(SellDate)&&double.IsNaN(CurrentPrice))
{
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,
Shares,
Utility.DateTimeToStringMMHDDHYYYY(PurchaseDate),
Utility.AddQuotes(Utility.FormatCurrency(PurchasePrice)),
Utility.AddQuotes(Utility.FormatCurrency(InitialStopLimit)),
Utility.AddQuotes(Utility.FormatCurrency(TrailingStopLimit)),
Utility.AddQuotes(Utility.DateTimeToStringMMHDDHYYYY(LastStopAdjustment)),
Utility.AddQuotes(Utility.FormatNumber(Volatility,2)),
Utility.AddQuotes(Utility.FormatNumber(Volume,0)),
Utility.AddQuotes(Utility.FormatCurrency(R)),
Utility.AddQuotes(Utility.FormatNumber(PositionRiskPercentDecimal,3)),
Utility.AddQuotes(Utility.FormatCurrency(C)),
Utility.AddQuotes(Utility.FormatCurrency(TotalRiskExposure)),
Utility.AddQuotes(Utility.FormatNumber(RMultiple,3)),
Utility.AddQuotes(RMultipleAsString),
Utility.IsEpoch(SellDate)?"N/A":Utility.DateTimeToStringMMHDDHYYYY(SellDate),
"N/A",
Utility.AddQuotes(Utility.FormatCurrency(Exposure)),
"N/A",
"N/A",
"N/A",
null==Comment?"":Comment
));
}
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}",
Symbol,
Shares,
Utility.DateTimeToStringMMHDDHYYYY(PurchaseDate),
Utility.AddQuotes(Utility.FormatCurrency(PurchasePrice)),
Utility.AddQuotes(Utility.FormatCurrency(InitialStopLimit)),
Utility.AddQuotes(Utility.FormatCurrency(TrailingStopLimit)),
Utility.IsEpoch(LastStopAdjustment)?"N/A":Utility.DateTimeToStringMMHDDHYYYY(LastStopAdjustment),
Utility.AddQuotes(Utility.FormatNumber(Volatility,2)),
Utility.AddQuotes(Utility.FormatNumber(Volume,0)),
Utility.AddQuotes(Utility.FormatCurrency(R)),
Utility.AddQuotes(Utility.FormatNumber(PositionRiskPercentDecimal,3)),
Utility.AddQuotes(Utility.FormatCurrency(C)),
Utility.AddQuotes(Utility.FormatCurrency(TotalRiskExposure)),
Utility.AddQuotes(Utility.FormatNumber(RMultiple,3)),
Utility.AddQuotes(RMultipleAsString),
Utility.IsEpoch(SellDate)?"N/A":Utility.DateTimeToStringMMHDDHYYYY(SellDate),
Utility.AddQuotes(Utility.FormatCurrency(CurrentPrice)),
Utility.AddQuotes(Utility.FormatCurrency(Exposure)),
Utility.AddQuotes(Utility.FormatCurrency(MarketValue)),
Utility.AddQuotes(Utility.FormatCurrency(GainLoss)),
Utility.FormatPercent(GainLossPcnt),
null==Comment?"":Comment
));
}
}
public static void DisplayHeader()
{
MDTrace.WriteLine(LogLevel.DEBUG,"Symbol,Shares,Purchase Date,Purchase Price,Initial Stop Limit,Trailing Stop Limit,Last Stop Adjustment,Volatility,Volume,R,PositionRiskPercentDecimal,C,TotalRiskExposure,RMultiple,RMultipleString,Sell Date,Sell Price,Exposure,Market Value,Gain Loss,Gain Loss(%),Comment");
}
}
// ****************************************************************************************************************************************************************
public class Positions:List<Position>
{
public Positions()
{
}
public Positions(Positions positions)
{
if(null==positions) return;
foreach(Position position in positions) Add(position);
}
public Positions(List<Position> positions)
{
if(null==positions) return;
foreach(Position position in positions) Add(position);
}
public Positions(Position position)
{
if(null==position) return;
Add(position);
}
public void Add(Positions positions)
{
if(null==positions) return;
foreach(Position position in positions) Add(position);
}
public int PositionsOn(DateTime purchaseDate)
{
return this.Count(x => x.PurchaseDate.Equals(purchaseDate));
}
public double GetExposure()
{
Positions openPositions=new Positions(this.Where(x => Utility.IsEpoch(x.SellDate)).ToList());
return (from Position position in openPositions select position.PurchasePrice*position.Shares).Sum();
}
public double GetMarketValue()
{
Positions closedPositions=new Positions(this.Where(x => !Utility.IsEpoch(x.SellDate)).ToList());
if(null==closedPositions||0==closedPositions.Count) return 0.00;
return closedPositions.Select(x => x.CurrentPrice*x.Shares).Sum();
}
public List<String> GetSymbols()
{
return (from Position position in this select position.Symbol).Distinct().ToList();
}
public double GetGainLoss()
{
Positions closedPositions=new Positions(this.Where(x => !Utility.IsEpoch(x.SellDate)).ToList());
if(null==closedPositions||0==closedPositions.Count) return 0.00;
double totalMarketValue=closedPositions.Select(x => x.Shares*x.CurrentPrice).Sum();
double totalExposure=closedPositions.Select(x => x.Shares*x.PurchasePrice).Sum();
return totalMarketValue-totalExposure;
}
public double GetGainLossPercent()
{
Positions closedPositions=new Positions(this.Where(x => !Utility.IsEpoch(x.SellDate)).ToList());
if(null==closedPositions||0==closedPositions.Count) return 0.00;
double totalMarketValue=closedPositions.Select(x => x.Shares*x.CurrentPrice).Sum();
double totalExposure=closedPositions.Select(x => x.Shares*x.PurchasePrice).Sum();
return (totalMarketValue-totalExposure)/totalExposure;
}
public NVPCollections ToNVPCollections()
{
NVPCollections nvpCollections=new NVPCollections();
foreach(Position position in this)
{
nvpCollections.Add(position.ToNVPCollection());
}
return nvpCollections;
}
public static Positions FromNVPCollections(NVPCollections nvpCollections)
{
Positions positions=new Positions();
foreach(NVPCollection nvpCollection in nvpCollections)
{
positions.Add(Position.FromNVPCollection(nvpCollection));
}
return positions;
}
public void AddFromNVPCollection(NVPCollection nvpCollection)
{
Add(Position.FromNVPCollection(nvpCollection));
}
public void DisplayTop(int count=10)
{
Positions positions=new Positions(this.OrderByDescending(x => x.GainLossPcnt).Take(count).ToList());
Position.DisplayHeader();
for(int index=0;index<positions.Count;index++)
{
Position position=positions[index];
position.Display();
}
}
public void DisplayBottom(int count=10)
{
Positions positions=new Positions(this.OrderBy(x => x.GainLossPcnt).Take(count).ToList());
Position.DisplayHeader();
for(int index=0;index<positions.Count;index++)
{
Position position=positions[index];
position.Display();
}
}
public void Display()
{
Position.DisplayHeader();
for(int index=0;index<Count;index++)
{
Position position=this[index];
position.Display();
}
MDTrace.WriteLine(LogLevel.DEBUG,"****************************************************************************************************************************");
}
}
}

View File

@@ -0,0 +1,70 @@
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.CMTrend
{
public class CMTPricingExceptions:List<CMTPricingException>
{
public NVPCollections ToNVPCollections()
{
NVPCollections nvpCollections=new NVPCollections();
foreach(CMTPricingException pricingException in this)
{
nvpCollections.Add(pricingException.ToNVPCollection());
}
return nvpCollections;
}
public static CMTPricingExceptions FromNVPCollections(NVPCollections nvpCollections)
{
CMTPricingExceptions pricingExcpetions=new CMTPricingExceptions();
foreach(NVPCollection nvpCollection in nvpCollections)
{
pricingExcpetions.Add(CMTPricingException.FromNVPCollection(nvpCollection));
}
return pricingExcpetions;
}
public void AddFromNVPCollection(NVPCollection nvpCollection)
{
Add(CMTPricingException.FromNVPCollection(nvpCollection));
}
}
public class CMTPricingException
{
public CMTPricingException()
{
}
public CMTPricingException(CMTPricingException pricingException)
{
this.Symbol=pricingException.Symbol;
this.ExceptionCount=pricingException.ExceptionCount;
}
public CMTPricingException(String symbol,int exceptionCount)
{
this.Symbol=symbol;
this.ExceptionCount=exceptionCount;
}
public String Symbol { get; set; }
public int ExceptionCount { get; set; }
public virtual NVPCollection ToNVPCollection()
{
NVPCollection nvpCollection=new NVPCollection();
nvpCollection.Add(new NVP("Symbol",Symbol.ToString()));
nvpCollection.Add(new NVP("ExceptionCount",ExceptionCount.ToString()));
return nvpCollection;
}
public static CMTPricingException FromNVPCollection(NVPCollection nvpCollection)
{
CMTPricingException pricingException=new CMTPricingException();
NVPDictionary nvpDictionary=nvpCollection.ToDictionary();
pricingException.Symbol=nvpDictionary["Symbol"].Get<String>();
pricingException.ExceptionCount=nvpDictionary["ExceptionCount"].Get<int>();
return pricingException;
}
}
}

View File

@@ -0,0 +1,221 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using MarketData.Utils;
using MarketData.Generator.Model;
namespace MarketData.Generator.CMTrend
{
public class CMTSessionParams
{
public DateTime LastUpdated { get; set; }
public DateTime TradeDate { get; set; }
public DateTime StartDate { get; set; }
public DateTime AnalysisDate { get; set; }
public CMTParams CMTParams { get; set; }
public ActivePositions ActivePositions { get; set; }
public Positions AllPositions { get; set; }
public CMTCandidates Candidates { get; set; }
public CMTPricingExceptions PricingExceptions { get; set; }
public StopLimits StopLimits { get; set; }
public double CashBalance { get; set; }
public double NonTradeableCash{ get; set; }
public double InitialCash { get; set; }
// This gets AllPositions+Positions
public Positions GetCombinedPositions()
{
Positions positions=new Positions();
foreach(Position position in AllPositions) positions.Add(position);
foreach(Position position in ActivePositions) positions.Add(position);
return positions;
}
}
// *****************************************************************************
public static class CMTSessionManager
{
public static bool SaveSession(CMTSessionParams sessionParams,String pathSessionFile)
{
try
{
if(null==pathSessionFile) return false;
pathSessionFile=GetSessionFileName(pathSessionFile);
FileStream outStream=new FileStream(pathSessionFile,FileMode.Create);
StreamWriter streamWriter=new StreamWriter(outStream);
streamWriter.WriteLine("CMTSESSIONv1.00");
streamWriter.WriteLine((new NVP("LastUpdated",sessionParams.LastUpdated.ToString())).ToString());
streamWriter.WriteLine((new NVP("TradeDate",sessionParams.TradeDate.ToShortDateString())).ToString());
streamWriter.WriteLine((new NVP("StartDate",sessionParams.StartDate.ToShortDateString())).ToString());
streamWriter.WriteLine((new NVP("AnalysisDate",sessionParams.AnalysisDate.ToShortDateString())).ToString());
streamWriter.WriteLine((new NVP("CashBalance",sessionParams.CashBalance.ToString())).ToString());
streamWriter.WriteLine((new NVP("NonTradeableCash",sessionParams.NonTradeableCash.ToString())).ToString());
NVPCollection configurationCollection=sessionParams.CMTParams.ToNVPCollection();
streamWriter.WriteLine(configurationCollection.ToString());
NVPCollections nvpPricingExceptionCollections=sessionParams.PricingExceptions.ToNVPCollections();
List<String> nvpPricingExceptionCollectionsList=nvpPricingExceptionCollections.ToList();
streamWriter.WriteLine((new NVP("PricingExceptions",nvpPricingExceptionCollectionsList.Count.ToString())).ToString());
foreach(String str in nvpPricingExceptionCollectionsList) streamWriter.WriteLine(str);
NVPCollections nvpCollections=sessionParams.ActivePositions.ToNVPCollections();
List<String> nvpActivePositionsStringList=nvpCollections.ToList();
streamWriter.WriteLine((new NVP("TotalActivePositions",nvpActivePositionsStringList.Count.ToString())).ToString());
foreach(String str in nvpActivePositionsStringList) streamWriter.WriteLine(str);
NVPCollections allPositionsCollections=sessionParams.AllPositions.ToNVPCollections();
List<String> nvpAllCollectionsStringList=allPositionsCollections.ToList();
streamWriter.WriteLine((new NVP("TotalPositions",nvpAllCollectionsStringList.Count.ToString())).ToString());
foreach(String str in nvpAllCollectionsStringList) streamWriter.WriteLine(str);
NVPCollections allCandidatesCollections=sessionParams.Candidates.ToNVPCollections();
List<String> nvpSetupsCollectionsStringList=allCandidatesCollections.ToList();
streamWriter.WriteLine((new NVP("TotalCandidates",nvpSetupsCollectionsStringList.Count.ToString())).ToString());
foreach(String str in nvpSetupsCollectionsStringList) streamWriter.WriteLine(str);
NVPCollections allStopLimitsCollections=sessionParams.StopLimits.ToNVPCollections();
List<String> nvpStopLimitsCollectionsStringList=allStopLimitsCollections.ToList();
streamWriter.WriteLine((new NVP("TotalStopLimits",nvpStopLimitsCollectionsStringList.Count.ToString())).ToString());
foreach(String str in nvpStopLimitsCollectionsStringList) streamWriter.WriteLine(str);
streamWriter.Flush();
outStream.Flush();
streamWriter.Close();
streamWriter.Dispose();
outStream.Close();
outStream.Dispose();
return true;
}
catch(Exception exception)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0}",exception.ToString()));
return false;
}
}
public static CMTSessionParams RestoreSession(String pathSessionFile)
{
FileStream inStream=null;
StreamReader streamReader=null;
try
{
pathSessionFile=GetSessionFileName(pathSessionFile);
if(!SessionAvailable(pathSessionFile)) return null;
CMTSessionParams sessionParams=new CMTSessionParams();
inStream=new FileStream(pathSessionFile,FileMode.Open);
streamReader=new StreamReader(inStream);
String versionInfo=streamReader.ReadLine();
if(!versionInfo.StartsWith("CMTSESSION")) return null;
double version=double.Parse(Utility.BetweenString(versionInfo,"v",null));
if(1.00!=version) return null;
NVP lastUpdated=new NVP(streamReader.ReadLine());
NVP tradeDate=new NVP(streamReader.ReadLine());
NVP startDate=new NVP(streamReader.ReadLine());
NVP analysisDate=new NVP(streamReader.ReadLine());
NVP cashBalance=new NVP(streamReader.ReadLine());
NVP nonTradeableCash=new NVP(streamReader.ReadLine());
sessionParams.LastUpdated=lastUpdated.Get<DateTime>();
sessionParams.TradeDate=tradeDate.Get<DateTime>();
sessionParams.StartDate=startDate.Get<DateTime>();
sessionParams.AnalysisDate=analysisDate.Get<DateTime>();
sessionParams.CashBalance=cashBalance.Get<double>();
sessionParams.NonTradeableCash=nonTradeableCash.Get<double>();
NVPCollection configurationCollection=new NVPCollection(streamReader.ReadLine());
sessionParams.CMTParams=CMTParams.FromNVPCollection(configurationCollection);
int totalPricingExceptions=(new NVP(streamReader.ReadLine())).Get<int>();
sessionParams.PricingExceptions=new CMTPricingExceptions();
for(int pricingExceptionIndex=0;pricingExceptionIndex<totalPricingExceptions;pricingExceptionIndex++)
{
NVPCollection nvpCollection=new NVPCollection(streamReader.ReadLine());
sessionParams.PricingExceptions.AddFromNVPCollection(nvpCollection);
}
int totalActivePositions=(new NVP(streamReader.ReadLine())).Get<int>();
sessionParams.ActivePositions=new ActivePositions();
for(int positionIndex=0;positionIndex<totalActivePositions;positionIndex++)
{
NVPCollection nvpCollection=new NVPCollection(streamReader.ReadLine());
sessionParams.ActivePositions.AddFromNVPCollection(nvpCollection);
}
int totalPositions=(new NVP(streamReader.ReadLine())).Get<int>();
NVPCollections nvpCollections=new NVPCollections();
for(int positionIndex=0;positionIndex<totalPositions;positionIndex++)
{
NVPCollection nvpCollection=new NVPCollection(streamReader.ReadLine());
nvpCollections.Add(nvpCollection);
}
int totalCandidates=(new NVP(streamReader.ReadLine())).Get<int>();
sessionParams.Candidates=new CMTCandidates();
for(int setupIndex=0;setupIndex<totalCandidates;setupIndex++)
{
NVPCollection nvpCollection=new NVPCollection(streamReader.ReadLine());
sessionParams.Candidates.AddFromNVPCollection(nvpCollection);
}
int totalStopLimits=(new NVP(streamReader.ReadLine())).Get<int>();
sessionParams.StopLimits=new StopLimits();
for(int stopLimitIndex=0;stopLimitIndex<totalStopLimits;stopLimitIndex++)
{
NVPCollection nvpCollection=new NVPCollection(streamReader.ReadLine());
sessionParams.StopLimits.AddFromNVPCollection(nvpCollection);
}
sessionParams.AllPositions=Positions.FromNVPCollections(nvpCollections);
inStream.Close();
inStream.Dispose();
inStream=null;
streamReader.Close();
streamReader.Dispose();
streamReader=null;
return sessionParams;
}
finally
{
if(null!=streamReader) streamReader.Close();
if(null!=inStream) inStream.Close();
}
}
public static String GetSessionFileName(String pathSessionFile)
{
if(null==pathSessionFile) return null;
String directory=Path.GetDirectoryName(pathSessionFile);
if("".Equals(directory)) directory=Directory.GetCurrentDirectory();
return directory+"/"+Path.GetFileNameWithoutExtension(pathSessionFile)+".TXT";
}
public static bool SessionAvailable(String pathSessionFile)
{
return IsValidSessionFile(pathSessionFile);
}
public static bool IsValidSessionFile(String pathSessionFile)
{
FileStream inStream=null;
StreamReader streamReader=null;
try
{
if(null==pathSessionFile) return false;
pathSessionFile=GetSessionFileName(pathSessionFile);
if(!File.Exists(pathSessionFile)) return false;
inStream=new FileStream(pathSessionFile,FileMode.Open);
streamReader=new StreamReader(inStream);
String versionInfo=streamReader.ReadLine();
if(!versionInfo.StartsWith("CMTSESSION")) return false;
double version=double.Parse(Utility.BetweenString(versionInfo,"v",null));
if(1.00!=version) return false;
return true;
}
catch(Exception)
{
return false;
}
finally
{
if(null!=streamReader) streamReader.Close();
if(null!=inStream) inStream.Close();
}
}
}
}

View File

@@ -0,0 +1,55 @@
using MarketData.DataAccess;
using MarketData.MarketDataModel;
using MarketData.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MarketData.Generator.CMTrend
{
public class CMTTrendGenerator
{
private CMTTrendGenerator()
{
}
public static CMTGeneratorResult GenerateCMTCandidates(DateTime tradeDate,CMTParams cmtParams,List<String> symbolsHeld)
{
CMTGeneratorResult cmtGeneratorResult=new CMTGeneratorResult();
try
{
List<String> symbols=PricingDA.GetSymbols();
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);
if(null==cmtCandidate) continue;
if(cmtCandidate.Violation) cmtGeneratorResult.CMTCandidatesWithViolation.Add(cmtCandidate);
else cmtGeneratorResult.CMTCandidates.Add(cmtCandidate);
}
if(null==cmtGeneratorResult.CMTCandidates||0==cmtGeneratorResult.CMTCandidates.Count)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("GenerateCMTCandidates. No candidates generated for trade date: {0}",tradeDate));
cmtGeneratorResult.Success=true;
return cmtGeneratorResult;
}
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Generated {0} candidates.",cmtGeneratorResult.CMTCandidates.Count));
cmtGeneratorResult.CMTCandidates.Sort();
MDTrace.WriteLine(LogLevel.DEBUG,CMTCandidate.Header());
foreach(CMTCandidate candidate in cmtGeneratorResult.CMTCandidates) MDTrace.WriteLine(LogLevel.DEBUG,candidate.ToString());
cmtGeneratorResult.Success=true;
return cmtGeneratorResult;
}
catch(Exception exception)
{
MDTrace.WriteLine(LogLevel.DEBUG,exception.ToString());
cmtGeneratorResult.Success=false;
cmtGeneratorResult.Messages.Add(exception.ToString());
return cmtGeneratorResult;
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,14 @@
using System;
namespace MarketData.Generator.CMTrend
{
public class CMTTrendModelResult
{
public CMTTrendModelResult()
{
}
public double CashBalance { get; set; }
public bool Success { get; set; }
public String Message { get; set; }
}
}

View File

@@ -196,8 +196,6 @@ namespace MarketData.Generator.MGSHMomentum
try
{
if(null==pathSessionFile)return 0.00;
// pathSessionFile=pathSessionFile.ToUpper();
// if(!pathSessionFile.EndsWith(".TXT")&&!pathSessionFile.EndsWith(".txt"))pathSessionFile+=".txt";
if(!File.Exists(pathSessionFile))return 0.00;
inStream =new FileStream(pathSessionFile,FileMode.Open);
streamReader=new StreamReader(inStream);
@@ -223,8 +221,6 @@ namespace MarketData.Generator.MGSHMomentum
try
{
if(null==pathSessionFile)return false;
// pathSessionFile=pathSessionFile.ToUpper();
// if(!pathSessionFile.EndsWith(".TXT")&&!pathSessionFile.EndsWith(".txt"))pathSessionFile+=".txt";
if(!File.Exists(pathSessionFile))return false;
inStream =new FileStream(pathSessionFile,FileMode.Open);
streamReader=new StreamReader(inStream);