| Overall Statistics |
|
Total Trades 28 Average Win 3.90% Average Loss -5.88% Compounding Annual Return -53.824% Drawdown 37.900% Expectancy -0.525 Net Profit -36.554% Sharpe Ratio -2.288 Loss Rate 71% Win Rate 29% Profit-Loss Ratio 0.66 Alpha -0.483 Beta 0.052 Annual Standard Deviation 0.221 Annual Variance 0.049 Information Ratio -0.097 Tracking Error 0.767 Treynor Ratio -9.763 Total Fees $4346.94 |
using QuantConnect.Brokerages;
using QuantConnect.Data;
using QuantConnect.Data.Consolidators;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;
using QuantConnect.Orders;
using QuantConnect.Securities;
using System.Drawing;
using QuantConnect.Statistics;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Algorithm.CSharp
{
/// <summary>
/// DeMark Strategy Algorithm.
/// This class has the methods for working with DeMark Setup Indicator.
/// </summary>
/// <remarks>
/// There is 3 timeframes supported by the strategy (H1, H4 and D1).
/// </remarks>
public class DeMarkAlgorithm : QCAlgorithm
{
enum Timeframe { H1, H4, D1 };
// Input Parameters
private bool OpenOnTrend = false;
private bool OpenOnPerfect = false;
private bool OpenOnCountdown = true;
private const bool UseTrailingStop = false;
private const Timeframe TimeFrame = Timeframe.H4;
private const decimal StopLoss = 0.04m;
private const decimal TakeProfit = 0.04m;
private const decimal InitialBalance = 100000m;
private const int ATRPeriod = 100;
private Symbol _tradeSymbol;
// Internal Variables
private RollingWindow<TradeBar> _bars;
private AverageTrueRange _atr;
private decimal _longStoploss;
private decimal _longTakeprofit;
private decimal _shortStoploss;
private decimal _shortTakeprofit;
private TradeBuilder _tradeBuilder;
private DeMarkSetup _longSetup, _shortSetup;
/// <summary>
/// Initialise the data and resolution required, as well as the cash and start-end dates for your algorithm. All algorithms must initialized.
/// </summary>
public override void Initialize()
{
// Backtest Parameters
SetStartDate(2018, 4, 1);
SetEndDate(2018, 11, 1);
SetCash(InitialBalance);
// Brokerage Model
SetBrokerageModel(BrokerageName.Bitfinex, AccountType.Margin);
// Symbol and Market Parameters
_tradeSymbol = QuantConnect.Symbol.Create("ETHUSD", SecurityType.Crypto, Market.Bitfinex);
Security security;
switch (TimeFrame)
{
case Timeframe.H1:
security = AddCrypto(_tradeSymbol, Resolution.Hour);
BrokerageModel.GetFeeModel(security);
// Consolidator
TradeBarConsolidator consolidator = new TradeBarConsolidator(1);
consolidator.DataConsolidated += BarHandler;
SubscriptionManager.AddConsolidator(_tradeSymbol, consolidator);
break;
case (Timeframe.H4):
security = AddCrypto(_tradeSymbol, Resolution.Hour);
BrokerageModel.GetFeeModel(security);
// Consolidator
TradeBarConsolidator fourHourConsolidator = new TradeBarConsolidator(TimeSpan.FromHours(4));
fourHourConsolidator.DataConsolidated += BarHandler;
SubscriptionManager.AddConsolidator(_tradeSymbol, fourHourConsolidator);
break;
case (Timeframe.D1):
security = AddCrypto(_tradeSymbol, Resolution.Daily);
BrokerageModel.GetFeeModel(security);
// Consolidator
TradeBarConsolidator dailyconsolidator = new TradeBarConsolidator(1);
dailyconsolidator.DataConsolidated += BarHandler;
SubscriptionManager.AddConsolidator(_tradeSymbol, dailyconsolidator);
break;
default:
Quit("Timeframe not supported");
break;
}
SetBenchmark(_tradeSymbol);
SetWarmup(1);
_atr = new AverageTrueRange(_tradeSymbol, ATRPeriod, MovingAverageType.Simple);
_bars = new RollingWindow<TradeBar>(15);
// Create charts for signals, stops and indicator
CreateChart();
_longSetup = new DeMarkSetup(Directions.Up);
_shortSetup = new DeMarkSetup(Directions.Dw);
// TradeBuilder for Balance Drawdown calculation
_tradeBuilder = new TradeBuilder(FillGroupingMethod.FlatToFlat, FillMatchingMethod.FIFO);
SetTradeBuilder(_tradeBuilder);
}
/// <summary>
/// OnData event is the primary entry point for the algorithm. Each new data point will be pumped in here.
/// </summary>
/// <param name="data">Slice object keyed by symbol containing the stock data</param>
public override void OnData(Slice data)
{
if (CheckStops())
{
ClosePositions();
}
}
/// <summary>
/// Called every order event.
/// </summary>
/// <param name="orderEvent">Object with order data</param>
/// <remarks>
/// Calculate stops values after order is filled.
/// </remarks>
public override void OnOrderEvent(OrderEvent orderEvent)
{
if (orderEvent.Status == OrderStatus.Filled)
{
if (orderEvent.Direction == OrderDirection.Buy)
{
DefineTakeProfit(orderEvent.FillPrice, Directions.Up);
DefineStopLoss(orderEvent.FillPrice, Directions.Up);
}
else if (orderEvent.Direction == OrderDirection.Sell)
{
DefineTakeProfit(orderEvent.FillPrice, Directions.Dw);
DefineStopLoss(orderEvent.FillPrice, Directions.Dw);
}
}
if (orderEvent.Status == OrderStatus.Canceled)
{
Log("Order Canceled");
}
else if (orderEvent.Status == OrderStatus.Invalid)
{
Log("Invalid Order");
}
}
/// <summary>
/// Called after strategy stop running.
/// </summary>
/// <remarks>
/// Close current position and calculate balance drawdown.
/// </remarks>
public override void OnEndOfAlgorithm()
{
ClosePositions();
decimal peak = InitialBalance;
decimal balance = peak;
decimal valley = 0m;
decimal balanceDrawdown = 0m;
foreach (var trade in _tradeBuilder.ClosedTrades)
{
balance += trade.ProfitLoss - trade.TotalFees;
if (balance > peak)
{
peak = balance;
valley = peak;
}
else
{
valley = balance;
}
if ((peak - valley) / peak > balanceDrawdown)
balanceDrawdown = (peak - valley) / peak;
}
Console.WriteLine($"Balance Drawdown % (From Risk Framework): {balanceDrawdown * 100}%");
}
/// <summary>
/// Handle bar information after bar consolidation.
/// </summary>
/// <param name="sender">The object calling <c>BarHandler</c></param>
/// <param name="consolidated">The bar values consolidated</param>
/// <remarks>
/// After bar is formed, calculate DeMark indicator and call trailing stop method.
/// </remarks>
private void BarHandler(object sender, TradeBar consolidated)
{
if (IsWarmingUp)
return;
_bars.Add(consolidated);
_atr.Update(consolidated);
PlotATRValue(_atr.Current.Value);
if (_bars.Count >= 1)
Plot("ChartSignals", "BarSerie", _bars[0].Close);
if (UseTrailingStop)
CheckTrailingStop();
if (_bars.Count >= 15)
{
switch (_longSetup.StepForward(_bars))
{
case SignalStatus.Trend:
if (!Portfolio[_tradeSymbol].Invested &&
OpenOnTrend)
{
OpenPosition(Directions.Up);
}
break;
// Perfect Setup
case SignalStatus.Perfect:
if (!Portfolio[_tradeSymbol].Invested &&
OpenOnPerfect)
{
OpenPosition(Directions.Up);
}
PlotLongPerfectSignal();
break;
// Countdown
case SignalStatus.Countdown:
if (!Portfolio[_tradeSymbol].Invested &&
OpenOnCountdown)
{
OpenPosition(Directions.Up);
}
PlotLongCountdownSignal();
break;
default:
break;
}
switch (_shortSetup.StepForward(_bars))
{
case SignalStatus.Trend:
if (!Portfolio[_tradeSymbol].Invested &&
OpenOnTrend)
{
OpenPosition(Directions.Dw);
}
break;
// Perfect Setup
case SignalStatus.Perfect:
if (!Portfolio[_tradeSymbol].Invested &&
OpenOnPerfect)
{
OpenPosition(Directions.Dw);
}
PlotShortPerfectSignal();
break;
// Countdown
case SignalStatus.Countdown:
if (!Portfolio[_tradeSymbol].Invested &&
OpenOnCountdown)
{
OpenPosition(Directions.Dw);
}
PlotShortCountdownSignal();
break;
default:
break;
}
}
}
/// <summary>
/// Check if current price reached stop loss or take profit of the
/// position openned (if any).
/// </summary>
/// <returns>If the position must be closed or not.</returns>
private bool CheckStops()
{
// Nothing to do if none position is open
if (!Portfolio[_tradeSymbol].Invested)
return (false);
if (Portfolio[_tradeSymbol].IsLong)
{
// Stop Loss
if (Securities[_tradeSymbol].Price <= _longStoploss)
{
PlotStopLoss(_longStoploss);
return (true);
}
// Take Profit
if (Securities[_tradeSymbol].Price >= _longTakeprofit
&& _longTakeprofit != 0m)
{
PlotTakeProfit(_longTakeprofit);
return (true);
}
}
else if (Portfolio[_tradeSymbol].IsShort)
{
// Stop Loss
if (Securities[_tradeSymbol].Price >= _shortStoploss
&& _shortStoploss != 0m)
{
PlotStopLoss(_shortStoploss);
return (true);
}
// Take Profit
if (Securities[_tradeSymbol].Price <= _shortTakeprofit)
{
PlotTakeProfit(_shortTakeprofit);
return (true);
}
}
return (false);
}
/// <summary>
/// Check rules for Trailing Stop Loss and call method for changing Stop Loss.
/// </summary>
private void CheckTrailingStop()
{
if (Portfolio[_tradeSymbol].Invested)
{
if (Portfolio[_tradeSymbol].IsLong)
{
decimal lowest = GetLowestLow();
if (_longStoploss < lowest
&& lowest < Securities[_tradeSymbol].Price)
{
ModifyStopLoss(lowest, Directions.Up);
}
}
else if (Portfolio[_tradeSymbol].IsShort)
{
decimal highest = GetHighestHigh();
if (_shortStoploss > highest
&& highest > Securities[_tradeSymbol].Price)
{
ModifyStopLoss(highest, Directions.Dw);
}
}
}
}
/// <summary>
/// Close opened positions.
/// </summary>
/// <remarks>
/// This function is called on stops and end of algorithm.
/// </remarks>
private void ClosePositions()
{
if (Portfolio[_tradeSymbol].Invested)
{
Liquidate(_tradeSymbol);
}
}
/// <summary>
/// Create chart for signals, stops and indicators.
/// </summary>
/// <remarks>
/// Plot Long or Short Perfection Setups, Countdowns signals,
/// Stop Loss, Take Profit, Stop Loss changed value by Trailing Stop.
/// </remarks>
private void CreateChart()
{
QuantConnect.Chart chart = new Chart("ChartSignals", ChartType.Stacked);
chart.AddSeries(new Series("BarSerie", SeriesType.Line));
chart.AddSeries(new Series("Long Perfect", SeriesType.Scatter,
"", Color.Blue, ScatterMarkerSymbol.Triangle));
chart.AddSeries(new Series("Long Countdown", SeriesType.Scatter,
"", Color.Green, ScatterMarkerSymbol.Triangle));
chart.AddSeries(new Series("Short Perfect", SeriesType.Scatter,
"", Color.Red, ScatterMarkerSymbol.TriangleDown));
chart.AddSeries(new Series("Short Countdown", SeriesType.Scatter,
"", Color.Yellow, ScatterMarkerSymbol.TriangleDown));
chart.AddSeries(new Series("TP", SeriesType.Scatter,
"", Color.Blue, ScatterMarkerSymbol.Circle));
chart.AddSeries(new Series("SL", SeriesType.Scatter,
"", Color.Red, ScatterMarkerSymbol.Circle));
chart.AddSeries(new Series("StopChanged", SeriesType.Scatter,
"", Color.Orange, ScatterMarkerSymbol.Circle));
AddChart(chart);
QuantConnect.Chart chartAtr = new Chart("ChartATR", ChartType.Stacked);
chartAtr.AddSeries(new Series("ATR", SeriesType.Line));
AddChart(chartAtr);
}
/// <summary>
/// Calculate Take Profit based on price and direction.
/// </summary>
/// <param name="value">The filled price must be passed as value</param>
/// <param name="direction">Direction can be Long or Short (Direction.Up or Direction.Dw)</param>
private void DefineTakeProfit(decimal value, Directions direction)
{
if (direction == Directions.Up)
{
//_longTakeprofit = value + (_atr.Current.Value * TakeProfit);
_longTakeprofit = value + (value * TakeProfit);
}
else
{
//_shortTakeprofit = value - (_atr.Current.Value * TakeProfit);
_shortTakeprofit = value - (value * TakeProfit);
}
}
/// <summary>
/// Calculate Stop Loss based on price and direction
/// </summary>
/// <param name="value">The filled price must be passed as value</param>
/// <param name="direction">Direction can be Long or Short (Direction.Up or Direction.Dw)</param>
private void DefineStopLoss(decimal value, Directions direction)
{
if (direction == Directions.Up)
{
//_longStoploss = value - (_atr.Current.Value * StopLoss);
_longStoploss = value - (value * StopLoss);
}
else
{
//_shortStoploss = value + (_atr.Current.Value * StopLoss);
_shortStoploss = value + (value * StopLoss);
}
}
/// <summary>
/// Compare two bars and get highest Bar High value.
/// </summary>
/// <returns>The highest High value of the two bars compared.</returns>
private decimal GetHighestHigh()
{
decimal[] array = { _bars[1].High, _bars[2].High };
return (array.Max());
}
/// <summary>
/// Compare two bars and get lowest Low value.
/// </summary>
/// <returns>>The lowest Low value of the two bars compared.</returns>
private decimal GetLowestLow()
{
decimal[] array = { _bars[1].Low, _bars[2].Low };
return (array.Min());
}
/// <summary>
/// Change value of Stop Loss and plot in the chart.
/// </summary>
/// <param name="value">Stop Loss new value</param>
/// <param name="direction">Long or Short</param>
/// <remarks>
/// </remarks>
private void ModifyStopLoss(decimal value, Directions direction)
{
if (direction == Directions.Up)
{
_longStoploss = value;
PlotStopLossChanged(_longStoploss);
}
else
{
_shortStoploss = value;
PlotStopLossChanged(_shortStoploss);
}
}
/// <summary>
/// Send market order based on parameter direction.
/// </summary>
/// <param name="direction">Long or Short</param>
private void OpenPosition(Directions direction)
{
if (direction == Directions.Up)
{
SetHoldings(_tradeSymbol, 1m, true);
}
else
{
SetHoldings(_tradeSymbol, -1m, true);
}
}
/// <summary>
/// Plot ATR value.
/// </summary>
/// <param name="value">ATR current value</param>
/// <remarks>
/// ATR is used for stops calculations.
/// </remarks>
private void PlotATRValue(decimal value)
{
Plot("ChartATR", "ATR", value);
}
/// <summary>
/// Plot the Countdown signal for Long direction.
/// </summary>
private void PlotLongCountdownSignal()
{
Plot("ChartSignals", "Long Countdown", _bars[0].Close);
}
/// <summary>
/// Plot Perfect Setup signal for Long direction.
/// </summary>
private void PlotLongPerfectSignal()
{
Plot("ChartSignals", "Long Perfect", _bars[0].Close);
}
/// <summary>
/// Pot Take Profit.
/// </summary>
/// <param name="value">Take Profit value</param>
private void PlotTakeProfit(decimal value)
{
Plot("ChartSignals", "TP", value);
}
/// <summary>
/// Plot Countdown signal for Short direction.
/// </summary>
private void PlotShortCountdownSignal()
{
Plot("ChartSignals", "Short Countdown", _bars[0].Close);
}
/// <summary>
/// Plot Perfect Setup signal for Short direction.
/// </summary>
private void PlotShortPerfectSignal()
{
Plot("ChartSignals", "Short Perfect", _bars[0].Close);
}
/// <summary>
/// Plot Stop Loss value.
/// </summary>
/// <param name="value">Stop Loss value</param>
private void PlotStopLoss(decimal value)
{
Plot("ChartSignals", "SL", value);
}
/// <summary>
/// Plot the new value of Stop Loss.
/// </summary>
/// <param name="value">The new Stop Loss value to be updated</param>
/// <remarks>
/// This function track Trailing Stop Loss working.
/// </remarks>
private void PlotStopLossChanged(decimal value)
{
Plot("ChartSignals", "StopChanged", value);
}
}
}namespace QuantConnect
{
enum Directions { Up, Dw }
public enum SignalStatus { None = 0, Trend = 1, Perfect = 2, Countdown = 3 }
/// <summary>
/// DeMark indicator algorithm.
/// All methods follows DeMark setups rules.
/// </summary>
public class DeMarkSetup
{
// Long or Short
private Directions Direction;
// Every iteration returns a SignalStatus, which can be None
private SignalStatus _status = SignalStatus.None;
// The bar values is passed every iteration and used in internal functions
private RollingWindow<TradeBar> _bar;
// If TD Setup is not perfected, try again once more
private bool _lookAgainForPerfection;
private bool _checkCountdownInitialization;
private bool _counterInitialized;
// Store the countdown bars
private List<TradeBar> _countdownBars = new List<TradeBar>();
/// <summary>
/// Constructor of DeMarkSetup class
/// </summary>
/// <param name="direction">Direction.Up or Direction.Dw</param>
internal DeMarkSetup(Directions direction)
{
Direction = direction;
}
/// <summary>
/// This function represents the iteration of DeMarkSetup.
/// Must be called every new bar.
/// </summary>
/// <param name="bar"> Store the bar values for use in internal functions </param>
/// <remarks>
/// Reset the signal to None,
/// check if TD Setup conditions are met,
/// check if TD Perfect Setup conditions are met, if not, try again
/// once more.
/// After TD Setup, check conditions to Countdown begins,
/// increment Countdown, if already initialized.
/// If variable Counter is higher than 12, check if Countdown signal happened.
/// </remarks>
public SignalStatus StepForward(RollingWindow<TradeBar> bar)
{
_bar = bar;
_status = SignalStatus.None;
if (_lookAgainForPerfection)
{
_lookAgainForPerfection = false;
if (PerfectSetup)
{
_status = SignalStatus.Perfect;
}
}
if (!_checkCountdownInitialization)
{
if (TDSetup)
{
_checkCountdownInitialization = true;
if (!PerfectSetup)
{
_lookAgainForPerfection = true;
_status = SignalStatus.Trend;
}
else
{
_status = SignalStatus.Perfect;
}
}
}
else
{
if (UpdateCountdownAndLookForSignal())
{
_status = SignalStatus.Countdown;
ResetCountdown();
}
}
return (_status);
}
/// <summary>
/// Method <c>TDSetup</c> check if the bar values return a complete TD Setup.
/// </summary>
/// <remarks>
/// The prerequisite for a TD Buy Setup is a Bearish TD
/// Price Flip, which indicates a switch from positive to
/// negative momentum.
///
/// The prerequisite for a TD Sell Setup is a Bullish TD
/// Price Flip, which indicates a switch from negative to
/// positive momentum.
///
/// TD Setup is an indicator that determines whether a
/// market is likely to be confined to a trading range or
/// starting a directional trend.
///
/// TD Setup is to be followed by TD Countdown.
///
/// A TD Buy Setup is that, after a bearish TD Price Flip,
/// there must be 9 consecutive closes, each one less than
/// the corresponding close four bars earlier.
///
/// If, at any point, the sequence of 9 consecutive closing
/// prices less than the closing price 4 bars earlier (up to
/// and including the close of TD Buy Setup Bar 9) is
/// interrupted, the developing TD Buy Setup must be
/// cancelled and must begin anew.
/// </remarks>
public bool TDSetup
{
get
{
if (Direction == Directions.Up)
{
return (_bar[0].Close < _bar[0 + 4].Close
&& _bar[1].Close < _bar[1 + 4].Close
&& _bar[2].Close < _bar[2 + 4].Close
&& _bar[3].Close < _bar[3 + 4].Close
&& _bar[4].Close < _bar[4 + 4].Close
&& _bar[5].Close < _bar[5 + 4].Close
&& _bar[6].Close < _bar[6 + 4].Close
&& _bar[7].Close < _bar[7 + 4].Close
&& _bar[8].Close < _bar[8 + 4].Close
&& _bar[9].Close > _bar[9 + 4].Close);
}
else
{
return (_bar[0].Close > _bar[0 + 4].Close
&& _bar[1].Close > _bar[1 + 4].Close
&& _bar[2].Close > _bar[2 + 4].Close
&& _bar[3].Close > _bar[3 + 4].Close
&& _bar[4].Close > _bar[4 + 4].Close
&& _bar[5].Close > _bar[5 + 4].Close
&& _bar[6].Close > _bar[6 + 4].Close
&& _bar[7].Close > _bar[7 + 4].Close
&& _bar[8].Close > _bar[8 + 4].Close
&& _bar[9].Close < _bar[9 + 4].Close);
}
}
}
/// <summary>
/// Method <c>PerfectSetup</c> check if bar values match
/// with Perfect Setup conditions.
/// </summary>
/// <remakrs>
/// <para>
/// TD Buy Setup “perfection” is the prerequisite for
/// entering a long position based on a completed TD Buy
/// Setup.
/// </para>
/// <para>
/// The low of Bar 8 or Bar 9 of the TD Buy Setup must be
/// less than, or equal to, the lows of Bar 6 and Bar 7 of the
/// TD Buy Setup.
/// </para>
/// </remakrs>
public bool PerfectSetup
{
get
{
if (Direction == Directions.Up)
{
return ((_bar[0].Low <= _bar[2].Low
&& _bar[0].Low <= _bar[3].Low)
|| (_bar[1].Low <= _bar[2].Low
&& _bar[1].Low <= _bar[3].Low));
}
else
{
return ((_bar[0].High >= _bar[2].High
&& _bar[0].High >= _bar[3].High)
|| (_bar[1].High >= _bar[2].High
&& _bar[1].High >= _bar[3].High));
}
}
}
/// <summary>
/// Check Countdown initialization conditions.
/// </summary>
/// <remarks>
/// To Initiate TD Sequential Buy Countdown:
/// <list type="bullet">
/// <item>
/// <description>
/// If Bar 9 of a TD Buy Setup also has a close less than, or
/// equal to, the low two bars earlier, then Bar 9 of a
/// TD Buy Setup becomes Bar 1 of a TD Buy Countdown.
/// </description>
/// </item>
/// </list>
/// <item>
/// <description>
/// If That condition is not met, then TD Buy Countdown Bar 1
/// is postponed until it does, and the TD Buy Countdown
/// continues until there are a total of 13 closes, each being
/// less than, or equal to, the low 2 bars earlier.
/// </description>
/// </item>
/// </list>
/// </remarks>
private bool CheckCountdownInitConditions()
{
if (Direction == Directions.Up)
{
return (_bar[0].Close <= _bar[2].Low);
}
else
{
return (_bar[0].Close >= _bar[2].High);
}
}
/// <summary>
/// This method handle Countdown rules.
/// </summary>
/// <remarks>
/// This function check for Countdown initialization
/// conditions. If Countdown have been initialized, than
/// increment counter.
/// If number of elements in CountdownBars is higher than 12,
/// check if the conditions of Countdown signal have been met.
/// </remarks>
private bool UpdateCountdownAndLookForSignal()
{
if (!_counterInitialized)
{
if (CheckCountdownInitConditions())
{
_counterInitialized = true;
_countdownBars.Add(_bar[0]);
}
}
else
{
// If Countdown Bar than increment Countdown
if (_countdownBars.Count <= 12)
{
if (Direction == Directions.Up)
{
if (_bar[0].Close <= _bar[2].Low)
{
_countdownBars.Insert(0, _bar[0]);
}
}
else
{
if (_bar[0].Close >= _bar[2].High)
{
_countdownBars.Insert(0, _bar[0]);
}
}
}
else
{
// Check Countdown signal
return (CheckCountdownSignal());
}
}
return (false);
}
/// <summary>
/// Method <c>CheckCountdownSignal</c> is only checked when the variable Counter is
/// higher than 12 and return true if conditions of countdown signal are met.
/// </summary>
/// <remarks>
/// To Complete a TD Sequential Buy Countdown two conditions must be met.
/// <list type="bullet">
/// <item>
/// <description>
/// The low of TD Buy Countdown Bar 13 must be less
/// than, or equal to, the close of TD Buy Countdown Bar 8.
/// </description>
/// </item>
/// <item>
/// <description>
/// The close of TD Buy Countdown Bar 13 must be less
/// than, or equal to, the low 2 bars earlier.
/// </description>
/// </item>
/// </list>
/// </remarks>
private bool CheckCountdownSignal()
{
if (Direction == Directions.Up)
{
return (
// check requirements for countdown signal
_bar[0].Low <= _countdownBars[5].Close &&
// check if it is a valid countdown bar
_bar[0].Close <= _bar[2].Low);
}
else if (Direction == Directions.Dw)
{
return (
// check requirements for countdown signal
_bar[0].High >= _countdownBars[5].Close &&
// check if it is a valid countdown bar
_bar[0].Close >= _bar[2].High);
}
return (false);
}
/// <summary>
/// Method <c>ResetCountdown</c> clear countdown bars list and
/// reset variables related with countdown.
/// </summary>
/// <remarks>
/// This function is called after a Countdown signal.
/// </remarks>
private void ResetCountdown()
{
_counterInitialized = false;
_checkCountdownInitialization = false;
_countdownBars.Clear();
}
}
}