436 lines
22 KiB
C#
436 lines
22 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using MarketData.MarketDataModel;
|
|
using MarketData.Utils;
|
|
using MarketData.Cache;
|
|
using MarketData.Numerical;
|
|
using MarketData.Generator.ModelGenerators;
|
|
using StopLimit=MarketData.Generator.Model.StopLimit;
|
|
|
|
namespace MarketData.Generator.MGSHMomentum
|
|
{
|
|
public class HedgeManager
|
|
{
|
|
private static int PRICING_DAYS = 120;
|
|
|
|
public HedgeManager()
|
|
{
|
|
}
|
|
|
|
public String HedgeShortSymbol { get; set; } = "SH";
|
|
|
|
public bool Verbose {get;set;} = false;
|
|
|
|
private void Display(String message)
|
|
{
|
|
if(Verbose)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,message);
|
|
}
|
|
}
|
|
|
|
public bool IsOpenHedgeIndicator(DateTime analysisDate, int hedgeCloseGreaterSMANDays=10, int hedgeBandBreakCheckDays=3)
|
|
{
|
|
Prices prices=GBPriceCache.GetInstance().GetPrices(HedgeShortSymbol, analysisDate, PRICING_DAYS);
|
|
|
|
if(null==prices || !prices[0].Date.Date.Equals(analysisDate.Date))
|
|
{
|
|
Display(String.Format("Cannot evaluate IsOpenHedgeIndicator for candidate {0} due to lack of current price on {1}",
|
|
HedgeShortSymbol,analysisDate.ToShortDateString()));
|
|
return false;
|
|
}
|
|
|
|
BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices); // K is upper band, KL1 below that. L is lower band, LP1 above that
|
|
BollingerBandElementsByDate bollingerBandElementsByDate = bollingerBands.GetBollingerBandElementsByDate();
|
|
if(!bollingerBandElementsByDate.ContainsKey(analysisDate))
|
|
{
|
|
Display(String.Format("Cannot evaluate IsOpenHedgeIndicator for candidate {0} due to lack of current price on {1}",HedgeShortSymbol,analysisDate.ToShortDateString()));
|
|
return false;
|
|
}
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[analysisDate];
|
|
|
|
if(bollingerBandElement.Close < bollingerBandElement.L )
|
|
{
|
|
Display(String.Format($"IsOpenHedgeIndicator AnalysisDate:{analysisDate.ToShortDateString()}"));
|
|
|
|
SlopeManager slopeManager = new SlopeManager(bollingerBandElementsByDate, analysisDate){Verbose=Verbose};
|
|
|
|
slopeManager.DisplaySlopes();
|
|
|
|
if(!CloseGreaterSMAN(analysisDate, bollingerBandElementsByDate, hedgeCloseGreaterSMANDays))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if(!BandBreakCheck(analysisDate, bollingerBandElementsByDate, hedgeBandBreakCheckDays)) // 3
|
|
{
|
|
return false;
|
|
}
|
|
|
|
int bucketDays=5;
|
|
int closeLessL=GetCloseLessL(analysisDate, bollingerBandElementsByDate, bucketDays);
|
|
int closeBetweenLAndLP1=GetCloseBetweenLAndLP1(analysisDate, bollingerBandElementsByDate, bucketDays);
|
|
int closeBetweenLP1AndSMAN=GetCloseBetweenLP1AndSMAN(analysisDate, bollingerBandElementsByDate, bucketDays);
|
|
int closeBetweenSMANAndKL1=GetCloseBetweenSMANAndKL1(analysisDate, bollingerBandElementsByDate, bucketDays);
|
|
int closeBetweenKL1AndK=GetCloseBetweenKL1AndK(analysisDate, bollingerBandElementsByDate, bucketDays);
|
|
int closeGreaterK=GetCloseGreaterK(analysisDate, bollingerBandElementsByDate, bucketDays);
|
|
Display($"Close buckets <L:{closeLessL} L/LP1:{closeBetweenLAndLP1} LP1/SMAN:{closeBetweenLP1AndSMAN} SMAN/KL1:{closeBetweenSMANAndKL1} KL1/K:{closeBetweenKL1AndK} >K:{closeGreaterK} KLSpread:{slopeManager.GetKLSpread()}");
|
|
|
|
// if the close is spending a lot of time between L and LP1 then make sure the overall volatility spread is widening sufficiently in the 5, 10, 30 day terms
|
|
if(closeBetweenLAndLP1 >= bucketDays && !slopeManager.IsMatchKLSpread("??+++"))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
Display(String.Format("Lower band break detected for {0} on {1} Price Close:{2} LP1:{3} ",
|
|
HedgeShortSymbol,
|
|
analysisDate.ToShortDateString(),
|
|
Utility.FormatCurrency(bollingerBandElement.Close),
|
|
Utility.FormatCurrency(bollingerBandElement.L)
|
|
));
|
|
Display($"TRUE");
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mainains and adjusts the stop limits for teh hedge position
|
|
/// </summary>
|
|
/// <param name="analysisDate"></param>
|
|
/// <param name="position"></param>
|
|
/// <param name="configuration"></param>
|
|
/// <returns></returns>
|
|
public StopLimit EvaluateStopPriceHedge(DateTime analysisDate, MGSHPosition position, MGSHConfiguration configuration)
|
|
{
|
|
DateGenerator dateGenerator=new DateGenerator();
|
|
Price currentPrice=GBPriceCache.GetInstance().GetPrice(position.Symbol,analysisDate);
|
|
double trailingStop=position.InitialStopLimit+Math.Floor((currentPrice.Low-position.PurchasePrice)/position.R)*position.R;
|
|
double trailingStopScaled=trailingStop;
|
|
double daysHeld=Math.Abs(dateGenerator.DaysBetweenActual(position.PurchaseDate,analysisDate));
|
|
|
|
if(Utility.IsEpoch(position.LastStopAdjustment)) // we've never adjusted the stop price
|
|
{
|
|
BollingerBandElementsByDate bollingerBandElementsByDate = GetBollingerBandElementsByDate(analysisDate);
|
|
if(null == bollingerBandElementsByDate)return null;
|
|
trailingStopScaled=GetHedgeStopLimitWithScalingAverageTrueRange(analysisDate,currentPrice,position,trailingStop, configuration.StopLimitScalingVolatilityDays, configuration.HedgeATRMultiplier);
|
|
trailingStop=Math.Max(trailingStop,trailingStopScaled);
|
|
if(trailingStop >= currentPrice.Low || trailingStop >= currentPrice.Close)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("The calculated trailing stop for {0} of {1} would be higher than the Low/Close of {2}.",
|
|
position.Symbol,
|
|
Utility.FormatCurrency(trailingStop),
|
|
Utility.FormatCurrency(currentPrice.Low)));
|
|
return null;
|
|
}
|
|
if(Numerics.Round(trailingStop) <= (Numerics.Round(position.TrailingStopLimit)))
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("The calculated trailing stop for {0} of {1} would be less than or equal to the existing stop limit of {2}.",
|
|
position.Symbol,
|
|
Utility.FormatCurrency(trailingStop),
|
|
Utility.FormatCurrency(position.TrailingStopLimit)));
|
|
return null;
|
|
}
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("****************************** A D J U S T S T O P L I M I T ************************"));
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Adjusting StopLimit on {0} after {1} days for {2} from {3} to {4}. Purchase Price: {5} Current Price:{6} Spread:{7} Shares:{8}",
|
|
analysisDate.ToShortDateString(),
|
|
daysHeld,
|
|
position.Symbol,
|
|
Utility.FormatCurrency(position.TrailingStopLimit),
|
|
Utility.FormatCurrency(trailingStop),
|
|
Utility.FormatCurrency(position.PurchasePrice),
|
|
Utility.FormatCurrency(currentPrice.Close),
|
|
Utility.FormatPercent((currentPrice.Close-trailingStop)/trailingStop),
|
|
Utility.FormatNumber(position.Shares,2)));
|
|
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("*****************************************************************************************"));
|
|
StopLimit newStopLimit=new StopLimit
|
|
{
|
|
StopLimitId=position.Symbol + Utility.DateTimeToStringYYYYMMDDMMSSTT(position.PurchaseDate),
|
|
Symbol=position.Symbol,
|
|
AnalysisDate=analysisDate,
|
|
PreviousStop=0.00==position.TrailingStopLimit?position.InitialStopLimit:position.TrailingStopLimit,
|
|
NewStop=trailingStop,
|
|
CurrentPriceLow=currentPrice.Low,
|
|
CurrentPriceClose=currentPrice.Close,
|
|
PriceTrendIndicatorSlope=0.00
|
|
};
|
|
position.TrailingStopLimit=trailingStop;
|
|
position.LastStopAdjustment=analysisDate;
|
|
return newStopLimit;
|
|
}
|
|
else // we have already made prior stop adjustments
|
|
{
|
|
int daysSinceLastStopAdjustment=Math.Abs(dateGenerator.DaysBetweenActual(position.LastStopAdjustment,analysisDate));
|
|
if(daysSinceLastStopAdjustment>=configuration.HedgeMinDaysBetweenStopAdjustments)
|
|
{
|
|
trailingStopScaled=GetHedgeStopLimitWithScalingAverageTrueRange(analysisDate,currentPrice,position,trailingStop,daysSinceLastStopAdjustment,configuration.HedgeATRMultiplier);
|
|
trailingStop=Math.Max(trailingStop,trailingStopScaled);
|
|
if(trailingStop>=currentPrice.Low||trailingStop>=currentPrice.Close)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("The calculated trailing stop for {0} of {1} would be higher than the Low/Close of {2}.",position.Symbol,Utility.FormatCurrency(trailingStop),Utility.FormatCurrency(currentPrice.Low)));
|
|
return null;
|
|
}
|
|
if(Numerics.Round(position.TrailingStopLimit) < Numerics.Round(trailingStop)) // round the stop limits to fractionals don't look like differences
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("****************************** A D J U S T S T O P L I M I T ************************"));
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Adjusting StopLimit on {0} after {1} days for {2} from {3} to {4}. Purchase Price: {5} Current Price:{6} Spread:{7} Shares:{8}",
|
|
analysisDate.ToShortDateString(),
|
|
daysHeld,
|
|
position.Symbol,
|
|
Utility.FormatCurrency(position.TrailingStopLimit),
|
|
Utility.FormatCurrency(trailingStop),
|
|
Utility.FormatCurrency(position.PurchasePrice),
|
|
Utility.FormatCurrency(currentPrice.Close),
|
|
Utility.FormatPercent((currentPrice.Close-trailingStop)/trailingStop),
|
|
Utility.FormatNumber(position.Shares,2)));
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("****************************************************************************************"));
|
|
StopLimit newStopLimit=new StopLimit
|
|
{
|
|
StopLimitId=position.Symbol + Utility.DateTimeToStringYYYYMMDDMMSSTT(position.PurchaseDate),
|
|
Symbol=position.Symbol,
|
|
AnalysisDate=analysisDate,
|
|
PreviousStop=0.00==position.TrailingStopLimit?position.InitialStopLimit:position.TrailingStopLimit,
|
|
NewStop=trailingStop,
|
|
CurrentPriceLow=currentPrice.Low,
|
|
CurrentPriceClose=currentPrice.Close,
|
|
PriceTrendIndicatorSlope=0.00
|
|
};
|
|
position.TrailingStopLimit=trailingStop;
|
|
position.LastStopAdjustment=analysisDate;
|
|
return newStopLimit;
|
|
}
|
|
else
|
|
{
|
|
double currentTrailingStopLimit=Numerics.Round(position.TrailingStopLimit);
|
|
double suggestedTrailingStopLimit=Numerics.Round(trailingStop);
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Not Adjusting Stop Limit for {0} because the new trailing stop limit would be less than or equal to the current trailing stop limit. Current Trailing Stop Limit:{1}, Calculated Trailing Stop Limit:{2}.",
|
|
position.Symbol,
|
|
Utility.FormatCurrency(currentTrailingStopLimit),
|
|
Utility.FormatCurrency(suggestedTrailingStopLimit)));
|
|
return null;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("The trailing stop for {0} was adjusted {1} days ago. HedgeMinDaysBetweenStopAdjustments is {2}",
|
|
position.Symbol,
|
|
daysSinceLastStopAdjustment,
|
|
configuration.HedgeMinDaysBetweenStopAdjustments));
|
|
return null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private int GetCloseLessL(DateTime analysisDate,BollingerBandElementsByDate bollingerBandElementsByDate, int days)
|
|
{
|
|
int count=0;
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
List<DateTime> dates = dateGenerator.GenerateHistoricalDates(analysisDate, days +1);
|
|
dates.RemoveAt(0);
|
|
foreach(DateTime date in dates)
|
|
{
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[date];
|
|
if(bollingerBandElement.Close < bollingerBandElement.L)count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private int GetCloseBetweenLAndLP1(DateTime analysisDate,BollingerBandElementsByDate bollingerBandElementsByDate, int days)
|
|
{
|
|
int count=0;
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
List<DateTime> dates = dateGenerator.GenerateHistoricalDates(analysisDate, days +1);
|
|
dates.RemoveAt(0);
|
|
foreach(DateTime date in dates)
|
|
{
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[date];
|
|
if(bollingerBandElement.Close >= bollingerBandElement.L && bollingerBandElement.Close<bollingerBandElement.LP1 )count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private int GetCloseBetweenLP1AndSMAN(DateTime analysisDate,BollingerBandElementsByDate bollingerBandElementsByDate, int days)
|
|
{
|
|
int count=0;
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
List<DateTime> dates = dateGenerator.GenerateHistoricalDates(analysisDate, days +1);
|
|
dates.RemoveAt(0);
|
|
foreach(DateTime date in dates)
|
|
{
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[date];
|
|
if(bollingerBandElement.Close >= bollingerBandElement.LP1 && bollingerBandElement.Close<bollingerBandElement.SMAN )count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private int GetCloseBetweenSMANAndKL1(DateTime analysisDate,BollingerBandElementsByDate bollingerBandElementsByDate, int days)
|
|
{
|
|
int count=0;
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
List<DateTime> dates = dateGenerator.GenerateHistoricalDates(analysisDate, days +1);
|
|
dates.RemoveAt(0);
|
|
foreach(DateTime date in dates)
|
|
{
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[date];
|
|
if(bollingerBandElement.Close >= bollingerBandElement.SMAN && bollingerBandElement.Close<bollingerBandElement.KL1 )count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private int GetCloseBetweenKL1AndK(DateTime analysisDate,BollingerBandElementsByDate bollingerBandElementsByDate, int days)
|
|
{
|
|
int count=0;
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
List<DateTime> dates = dateGenerator.GenerateHistoricalDates(analysisDate, days +1);
|
|
dates.RemoveAt(0);
|
|
foreach(DateTime date in dates)
|
|
{
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[date];
|
|
if(bollingerBandElement.Close >= bollingerBandElement.KL1 && bollingerBandElement.Close<bollingerBandElement.K )count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private int GetCloseGreaterK(DateTime analysisDate,BollingerBandElementsByDate bollingerBandElementsByDate, int days)
|
|
{
|
|
int count=0;
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
List<DateTime> dates = dateGenerator.GenerateHistoricalDates(analysisDate, days +1);
|
|
dates.RemoveAt(0);
|
|
foreach(DateTime date in dates)
|
|
{
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[date];
|
|
if(bollingerBandElement.Close > bollingerBandElement.K )count++;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
private bool BandBreakCheck(DateTime analysisDate,BollingerBandElementsByDate bollingerBandElementsByDate, int days)
|
|
{
|
|
int lowLessLP1=0;
|
|
int closeLessLP1=0;
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
List<DateTime> dates = dateGenerator.GenerateHistoricalDates(analysisDate, days +1);
|
|
dates.RemoveAt(0);
|
|
foreach(DateTime date in dates)
|
|
{
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[date];
|
|
if(bollingerBandElement.Low <= bollingerBandElement.LP1)lowLessLP1++;
|
|
if(bollingerBandElement.Close <= bollingerBandElement.LP1)closeLessLP1++;
|
|
}
|
|
return (lowLessLP1 >= days) && (closeLessLP1 >= days);
|
|
}
|
|
|
|
private bool CloseGreaterSMAN(DateTime analysisDate, BollingerBandElementsByDate bollingerBandElementsByDate, int days)
|
|
{
|
|
DateGenerator dateGenerator = new DateGenerator();
|
|
List<DateTime> dates = dateGenerator.GenerateHistoricalDates(analysisDate, days + 1);
|
|
dates.RemoveAt(0);
|
|
foreach (DateTime date in dates)
|
|
{
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[date];
|
|
if (bollingerBandElement.Close > bollingerBandElement.SMAN) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// This is used to trigger an adjustment to the stop price.
|
|
/// </summary>
|
|
/// <param name="analysisDate"></param>
|
|
/// <param name="position"></param>
|
|
/// <returns></returns>
|
|
public bool IsLowerBandBreakIndicator(DateTime analysisDate, MGSHPosition position)
|
|
{
|
|
BollingerBandElementsByDate bollingerBandElementsByDate = GetBollingerBandElementsByDate(analysisDate);
|
|
if (null == bollingerBandElementsByDate) return false;
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[analysisDate];
|
|
|
|
if (bollingerBandElement.High > bollingerBandElement.K)
|
|
{
|
|
Display(String.Format("+++ [1] Upper band break detected for {0} on {1} Purchase Date:{2} Purchase Price:{3} Price Close:{4} Price High:{5} Price High(hF):{6} KL1:{7}",
|
|
HedgeShortSymbol,
|
|
analysisDate.ToShortDateString(),
|
|
position.PurchaseDate.ToShortDateString(),
|
|
Utility.FormatCurrency(position.PurchasePrice),
|
|
Utility.FormatCurrency(bollingerBandElement.Close),
|
|
Utility.FormatCurrency(bollingerBandElement.High),
|
|
Utility.FormatCurrency(bollingerBandElement.High),
|
|
Utility.FormatCurrency(bollingerBandElement.K)
|
|
));
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private double GetHedgeStopLimitWithScalingAverageTrueRange(DateTime analysisDate,Price currentPrice,MGSHPosition position,double stopLimitNonScaled, int stopLimitScalingVolatilityDays, double hedgeATRMultiplier)
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("GetHedgeStopLimitWithScalingAverageTrueRange: Symbol:{0}",position.Symbol));
|
|
double volatility=double.NaN;
|
|
|
|
volatility=VolatilityGenerator.CalculateVolatility(position.Symbol,analysisDate,stopLimitScalingVolatilityDays, hedgeATRMultiplier);
|
|
if(double.IsNaN(volatility))
|
|
{
|
|
MDTrace.WriteLine(LogLevel.DEBUG,String.Format("Unable to calculate AverageTrueRange for {0} on {1}. Using non-scaled stop limit.",position.Symbol,analysisDate.ToShortDateString()));
|
|
return stopLimitNonScaled;
|
|
}
|
|
double stopLimit = ((currentPrice.High + currentPrice.Low)/2.00) - volatility; // We base the stop off of the midpoint of the high and the low
|
|
return stopLimit;
|
|
}
|
|
|
|
private BollingerBandElementsByDate GetBollingerBandElementsByDate(DateTime analysisDate)
|
|
{
|
|
Prices prices=GBPriceCache.GetInstance().GetPrices(HedgeShortSymbol, analysisDate, PRICING_DAYS);
|
|
if(null==prices||!prices[0].Date.Date.Equals(analysisDate.Date))
|
|
{
|
|
Display(String.Format("Cannot evaluate IsHedgeCloseIndicatorOn for candidate {0} due to lack of current price on {1}",
|
|
HedgeShortSymbol,analysisDate.ToShortDateString()));
|
|
return null;
|
|
}
|
|
BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices); // K is upper band, KL1 below that. L is lower band, LP1 above that
|
|
BollingerBandElementsByDate bollingerBandElementsByDate = bollingerBands.GetBollingerBandElementsByDate();
|
|
if(!bollingerBandElementsByDate.ContainsKey(analysisDate))
|
|
{
|
|
Display(String.Format("Cannot evaluate IsHedgeCloseIndicatorOn for candidate {0} due to lack of current price on {1}",
|
|
HedgeShortSymbol,analysisDate.ToShortDateString()));
|
|
return null;
|
|
}
|
|
return bollingerBandElementsByDate;
|
|
}
|
|
|
|
public void DisplayBandSlopes(DateTime analysisDate)
|
|
{
|
|
Display($"***** B A N D S L O P E S {analysisDate.ToShortDateString()} *****");
|
|
|
|
Prices prices=GBPriceCache.GetInstance().GetPrices(HedgeShortSymbol, analysisDate, PRICING_DAYS);
|
|
if(null==prices||!prices[0].Date.Date.Equals(analysisDate.Date))
|
|
{
|
|
Display(String.Format("Cannot evaluate IsHedgeCloseIndicatorOn for candidate {0} due to lack of current price on {1}",
|
|
HedgeShortSymbol,analysisDate.ToShortDateString()));
|
|
return;
|
|
}
|
|
BollingerBands bollingerBands=BollingerBandGenerator.GenerateBollingerBands(prices); // K is upper band, KL1 below that. L is lower band, LP1 above that
|
|
BollingerBandElementsByDate bollingerBandElementsByDate = bollingerBands.GetBollingerBandElementsByDate();
|
|
if(!bollingerBandElementsByDate.ContainsKey(analysisDate))
|
|
{
|
|
Display(String.Format("Cannot evaluate IsHedgeCloseIndicatorOn for candidate {0} due to lack of current price on {1}",
|
|
HedgeShortSymbol,analysisDate.ToShortDateString()));
|
|
return;
|
|
}
|
|
|
|
BollingerBandElement bollingerBandElement = bollingerBandElementsByDate[analysisDate];
|
|
|
|
SlopeManager slopeManager = new SlopeManager(bollingerBandElementsByDate, analysisDate){Verbose=true};
|
|
|
|
Display("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
|
slopeManager.DisplaySlopes();
|
|
Display("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
|
slopeManager.DisplaySlopesNumeric();
|
|
Display("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
|
|
}
|
|
}
|
|
}
|