Added EvaluateStopOnUpTrend. The default is FALSE. This worked out well in backtests.

This commit is contained in:
2025-02-22 22:17:03 -05:00
parent e50ac03b33
commit eda09a7f4f
2 changed files with 53 additions and 12 deletions

View File

@@ -65,6 +65,7 @@ namespace MarketData.Generator.CMTrend
}
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Done, took {0}(ms)",profiler.End()));
}
public static ModelPerformanceSeries GetModelPerformance(String paramPathSessionFileName)
{
try
@@ -78,6 +79,7 @@ namespace MarketData.Generator.CMTrend
return null;
}
}
// Calcualtes the expectation for the model ( Percent of Winning Trades * Average Gain)/(Percent Losing Trades * Average Loss)
// The expectation should be above zero
public static ModelStatistics GetModelStatistics(CMTSessionParams sessionParams)
@@ -111,6 +113,7 @@ namespace MarketData.Generator.CMTrend
return modelStatistics;
}
}
public static ModelPerformanceSeries GetModelPerformance(CMTSessionParams sessionParams)
{
Profiler profiler=new Profiler();
@@ -203,6 +206,7 @@ namespace MarketData.Generator.CMTrend
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Done, total took {0}(ms)",profiler.End()));
}
}
// ******************************************************************************************************************************************************
//************************************************************** D I S P L A Y S E S S I O N *****************************************************
// ******************************************************************************************************************************************************
@@ -350,6 +354,7 @@ namespace MarketData.Generator.CMTrend
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Average RProfit {0}R per trade (expectancy)",Utility.FormatNumber((totalRWinners+totalRLosers)/totalTrades,2,false)));
GBPriceCache.GetInstance().Dispose();
}
// ******************************************************************************************************************************************************
// ****************************************************************** E N T R Y T E S T *****************************************************************
// ******************************************************************************************************************************************************
@@ -482,6 +487,7 @@ namespace MarketData.Generator.CMTrend
GBPriceCache.GetInstance().Dispose();
}
}
// ******************************************************************************************************************************************************
// ****************************************************************** C L O S E **********************************************************************
// ******************************************************************************************************************************************************
@@ -534,6 +540,7 @@ namespace MarketData.Generator.CMTrend
SaveSession();
return true;
}
// ******************************************************************************************************************************************************
// *************************************************************************** E D I T ******************************************************************
// ******************************************************************************************************************************************************
@@ -581,6 +588,7 @@ namespace MarketData.Generator.CMTrend
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Position for symbol '{0}' purchased on {1} has been modified and saved.",symbol,purchaseDate.ToShortDateString()));
return true;
}
// ******************************************************************************************************************************************************
// ****************************************************************** D A I L Y *****************************************************************
// ******************************************************************************************************************************************************
@@ -687,6 +695,7 @@ namespace MarketData.Generator.CMTrend
GBPriceCache.GetInstance().Dispose();
}
}
// ******************************************************************************************************************************************************
// ****************************************************************** B A C K T E S T *****************************************************************
// ******************************************************************************************************************************************************
@@ -803,6 +812,7 @@ namespace MarketData.Generator.CMTrend
GBPriceCache.GetInstance().Dispose();
}
}
public void RunTrendTemplate(DateTime? analysisDate=null)
{
try
@@ -844,6 +854,7 @@ namespace MarketData.Generator.CMTrend
GBPriceCache.GetInstance().Dispose();
}
}
// ***********************************************************************************************************************************************************************
// *********************************************************************** M A N A G E O P E N P O S I T I O N S *****************************************************
// ***********************************************************************************************************************************************************************
@@ -922,6 +933,7 @@ namespace MarketData.Generator.CMTrend
}
}
}
// **********************************************************************************************************************************************************
// ***************************************************** M O V I N G A V E R A G E B R E A K C H E C K *************************************************
// **********************************************************************************************************************************************************
@@ -963,6 +975,7 @@ namespace MarketData.Generator.CMTrend
}
return false;
}
// **********************************************************************************************************************************************************
// ***************************************************** S T O P L I M I T C O L L E C T I O N M A I N T E N A N C E ***********************************
// **********************************************************************************************************************************************************
@@ -970,6 +983,7 @@ namespace MarketData.Generator.CMTrend
{
StopLimits.Add(stopLimit);
}
// **********************************************************************************************************************************************************
// *********************************************** P R I C I N G E X C E P T I O N C O L L E C T I O N M A I N T E N A N C E ***************************
// **********************************************************************************************************************************************************
@@ -980,18 +994,21 @@ namespace MarketData.Generator.CMTrend
else pricingException.ExceptionCount++;
return pricingException.ExceptionCount;
}
private void RemovePricingException(String symbol)
{
CMTPricingException pricingException=PricingExceptions.Where(x => x.Symbol.Equals(symbol)).FirstOrDefault();
if(null==pricingException) return;
PricingExceptions.Remove(pricingException);
}
private bool HasPricingException(String symbol)
{
CMTPricingException pricingException=PricingExceptions.Where(x => x.Symbol.Equals(symbol)).FirstOrDefault();
if(null==pricingException) return false;
return true;
}
// ***************************************************************************************************************************************************
// **************************************************************** S E L L P O S I T I O N S *****************************************************
// ***************************************************************************************************************************************************
@@ -1003,6 +1020,7 @@ namespace MarketData.Generator.CMTrend
SellPosition(position,sellDate,comment);
}
}
private void SellPosition(Position position,DateTime sellDate,String comment)
{
position.SellDate=sellDate;
@@ -1025,6 +1043,7 @@ namespace MarketData.Generator.CMTrend
}
else position.CurrentPrice=price.Close;
}
// ***************************************************************************************************************************************************
// **************************************************************** B U Y C A N D I D A T E S *****************************************************
// ***************************************************************************************************************************************************
@@ -1266,10 +1285,10 @@ namespace MarketData.Generator.CMTrend
return null;
}
}
// ***************************************************************************************************************************************************
// ***************************************************************** P O S I T I O N S I Z I N G **************************************************
// ***************************************************************************************************************************************************
private Positions PerformPositionSizing(Positions positions,double availableCash,DateTime tradeDate)
{
return PerformPositionSizingTotalRisk(positions, availableCash, tradeDate);
@@ -1304,6 +1323,7 @@ namespace MarketData.Generator.CMTrend
}
return acceptedPositions;
}
// ***************************************************************************************************************************************************
// ************************************************************** S T O P L I M I T S *************************************************************
// ***************************************************************************************************************************************************
@@ -1311,11 +1331,12 @@ namespace MarketData.Generator.CMTrend
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("EvaluateStopPrice: {0} on {1}",position.Symbol,tradeDate.ToShortDateString()));
DateGenerator dateGenerator=new DateGenerator();
Prices prices=GBPriceCache.GetInstance().GetPrices(position.Symbol,tradeDate,Parameters.PriceTrendDays); // only adjust stops if we are trending up
PriceTrendIndicatorResult priceTrendIndicatorResult=PriceTrendIndicator.IsUptrend(prices,Parameters.PriceTrendDays);
if(!priceTrendIndicatorResult.IsUpTrend)
Prices prices = GBPriceCache.GetInstance().GetPrices(position.Symbol, tradeDate, Parameters.PriceTrendDays); // only adjust stops if we are trending up
PriceTrendIndicatorResult priceTrendIndicatorResult = PriceTrendIndicator.IsUptrend(prices, Parameters.PriceTrendDays);
if(Parameters.EvaluateStopOnUpTrend && !priceTrendIndicatorResult.IsUpTrend)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("{0} does not have upward price trend (higher highs and higher lows for {1} consecutive days), will not adjust stop price",position.Symbol,Parameters.PriceTrendDays));
MDTrace.WriteLine(LogLevel.DEBUG, String.Format("{0} does not have upward price trend (higher highs and higher lows for {1} consecutive days), will not adjust stop price", position.Symbol, Parameters.PriceTrendDays));
return;
}
double trailingStop=position.InitialStopLimit+Math.Floor((currentPrice.Low-position.PurchasePrice)/position.R)*position.R; // where R = Risk Per Share in $
@@ -1414,6 +1435,7 @@ namespace MarketData.Generator.CMTrend
}
}
}
private double GetStopLimitWithScalingAverageTrueRange(DateTime tradeDate,Price currentPrice,Position position,double stopLimitNonScaled)
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("GetStopLimitWithScalingAverageTrueRange: Symbol:{0} RMultiple={1}",position.Symbol,position.RMultiple));
@@ -1441,6 +1463,7 @@ namespace MarketData.Generator.CMTrend
double stopLimit=currentPrice.Low-volatility; // We base the stop off of the low in order to give a bit more breathing room in the stop in the event that we have a wide spread between the close and the low. Backtested currentPrice.Close vs currentPrice.Low and basing off the low yields better results.
return stopLimit;
}
// ***************************************************************************************************************************************************
// ************************************************************* M A N A G E S E T U P S ***********************************************************
// ***************************************************************************************************************************************************
@@ -1461,6 +1484,7 @@ namespace MarketData.Generator.CMTrend
AddCandidate(mmCandidate);
}
}
private void ExpireCandidates(DateTime tradeDate)
{
List<CMTCandidate> candidatesToRemove=new List<CMTCandidate>();
@@ -1472,18 +1496,21 @@ namespace MarketData.Generator.CMTrend
}
foreach(CMTCandidate candidate in candidatesToRemove) Candidates.Remove(candidate);
}
private void AddCandidate(CMTCandidate candidate)
{
if(null==Candidates) Candidates=new CMTCandidates();
if(Candidates.Any(x => x.Symbol.Equals(candidate.Symbol))) return;
Candidates.Add(candidate);
}
private void RemoveCandidate(CMTCandidate candidate)
{
if(null==Candidates) Candidates=new CMTCandidates();
if(!Candidates.Any(x => x.Symbol.Equals(candidate.Symbol))) return;
Candidates.Remove(Candidates.Where(x => x.Symbol.Equals(candidate.Symbol)).FirstOrDefault());
}
// ***************************************************************************************************************************************************
// ************************************************************************ M A R K E T C O N D I T I O N S ***************************************
// ***************************************************************************************************************************************************
@@ -1521,6 +1548,7 @@ namespace MarketData.Generator.CMTrend
}
return result;
}
// Determine volatility based on ^VIX bollinger L band break on the close within 60 days prior
private static bool IsTradeableVolatilityEnvironment(DateTime tradeDate,CMTParams cmtParams)
{
@@ -1540,6 +1568,7 @@ namespace MarketData.Generator.CMTrend
}
return result;
}
// ***************************************************************************************************************************************************
// ************************************************************************ G E T P R I C E ******************************************************
// ***************************************************************************************************************************************************
@@ -1551,6 +1580,7 @@ namespace MarketData.Generator.CMTrend
if(null==price) price=GBPriceCache.GetInstance().GetPrice(symbol,dateGenerator.FindPrevBusinessDay(priceDate));
return price;
}
// *********************************************************************************************************************************************************************
// *********************************************************************************************************************************************************************
// *********************************************************************************************************************************************************************
@@ -1587,6 +1617,7 @@ namespace MarketData.Generator.CMTrend
MDTrace.WriteLine(LogLevel.DEBUG,"***************************************************************************************************************************");
}
}
public double GetRealtimeGainLoss(DateTime tradeDate)
{
int count=ActivePositions.Count;
@@ -1600,6 +1631,7 @@ namespace MarketData.Generator.CMTrend
}
return gainLoss;
}
private void DisplayBalance()
{
MDTrace.WriteLine(LogLevel.DEBUG,"EXPOSURE,AVAILABLE CASH,TOTAL ACCOUNT");
@@ -1618,6 +1650,7 @@ namespace MarketData.Generator.CMTrend
Utility.AddQuotes(Utility.FormatCurrency(ActivePositions.GetExposure()+CashBalance))));
}
}
private void DisplayBalanceFromPositions()
{
MDTrace.WriteLine(LogLevel.DEBUG,"EXPOSURE,GAIN/LOSS,GAIN/LOSS(%),AVAILABLE CASH,TOTAL ACCOUNT");
@@ -1628,6 +1661,7 @@ namespace MarketData.Generator.CMTrend
Utility.AddQuotes(Utility.FormatCurrency(CashBalance)),
Utility.AddQuotes(Utility.FormatCurrency(ActivePositions.GetMarketValue()+CashBalance))));
}
private void DisplayBalanceFromAllPositions()
{
MDTrace.WriteLine(LogLevel.DEBUG,"EXPOSURE,GAIN/LOSS,GAIN/LOSS(%),AVAILABLE CASH,TOTAL ACCOUNT");
@@ -1691,6 +1725,7 @@ namespace MarketData.Generator.CMTrend
return null;
}
}
public void SaveSession()
{
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Saving session to '{0}'",PathSessionFileName));
@@ -1709,6 +1744,7 @@ namespace MarketData.Generator.CMTrend
sessionParams.NonTradeableCash=NonTradeableCash;
CMTSessionManager.SaveSession(sessionParams,PathSessionFileName);
}
public bool BackupSession()
{
String[] parts=PathSessionFileName.Split('.');