chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:02:50 +08:00
commit 0fc60fdcb1
5008 changed files with 910633 additions and 0 deletions
+51
View File
@@ -0,0 +1,51 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the Absolute Price Oscillator (APO)
/// The Absolute Price Oscillator is calculated using the following formula:
/// APO[i] = FastMA[i] - SlowMA[i]
/// </summary>
/// <remarks>
/// The Absolute Price Oscillator is the same as a MACD with the signal period equal to the slow period.
/// </remarks>
public class AbsolutePriceOscillator : MovingAverageConvergenceDivergence
{
/// <summary>
/// Initializes a new instance of the <see cref="AbsolutePriceOscillator"/> class using the specified name and parameters.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="fastPeriod">The fast moving average period</param>
/// <param name="slowPeriod">The slow moving average period</param>
/// <param name="movingAverageType">The type of moving average to use</param>
public AbsolutePriceOscillator(string name, int fastPeriod, int slowPeriod, MovingAverageType movingAverageType = MovingAverageType.Simple)
: base(name, fastPeriod, slowPeriod, slowPeriod, movingAverageType)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AbsolutePriceOscillator"/> class using the specified parameters.
/// </summary>
/// <param name="fastPeriod">The fast moving average period</param>
/// <param name="slowPeriod">The slow moving average period</param>
/// <param name="movingAverageType">The type of moving average to use</param>
public AbsolutePriceOscillator(int fastPeriod, int slowPeriod, MovingAverageType movingAverageType = MovingAverageType.Simple)
: this($"APO({fastPeriod},{slowPeriod})", fastPeriod, slowPeriod, movingAverageType)
{
}
}
}
+127
View File
@@ -0,0 +1,127 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Acceleration Bands created by Price Headley plots upper and lower envelope bands around a moving average.
/// </summary>
/// <seealso cref="Indicators.IndicatorBase{IBaseDataBar}" />
public class AccelerationBands : IndicatorBase<IBaseDataBar>, IIndicatorWarmUpPeriodProvider
{
private readonly decimal _width;
/// <summary>
/// Gets the type of moving average
/// </summary>
public MovingAverageType MovingAverageType { get; }
/// <summary>
/// Gets the middle acceleration band (moving average)
/// </summary>
public IndicatorBase<IndicatorDataPoint> MiddleBand { get; }
/// <summary>
/// Gets the upper acceleration band (High * ( 1 + Width * (High - Low) / (High + Low)))
/// </summary>
public IndicatorBase<IndicatorDataPoint> UpperBand { get; }
/// <summary>
/// Gets the lower acceleration band (Low * (1 - Width * (High - Low)/ (High + Low)))
/// </summary>
public IndicatorBase<IndicatorDataPoint> LowerBand { get; }
/// <summary>
/// Initializes a new instance of the <see cref="AccelerationBands" /> class.
/// </summary>
/// <param name="name">The name of this indicator.</param>
/// <param name="period">The period of the three moving average (middle, upper and lower band).</param>
/// <param name="width">A coefficient specifying the distance between the middle band and upper or lower bands.</param>
/// <param name="movingAverageType">Type of the moving average.</param>
public AccelerationBands(string name, int period, decimal width,
MovingAverageType movingAverageType = MovingAverageType.Simple)
: base(name)
{
WarmUpPeriod = period;
_width = width;
MovingAverageType = movingAverageType;
MiddleBand = movingAverageType.AsIndicator(name + "_MiddleBand", period);
LowerBand = movingAverageType.AsIndicator(name + "_LowerBand", period);
UpperBand = movingAverageType.AsIndicator(name + "_UpperBand", period);
}
/// <summary>
/// Initializes a new instance of the <see cref="AccelerationBands" /> class.
/// </summary>
/// <param name="period">The period of the three moving average (middle, upper and lower band).</param>
/// <param name="width">A coefficient specifying the distance between the middle band and upper or lower bands.</param>
/// <param name="movingAverageType">Type of the moving average.</param>
public AccelerationBands(int period, decimal width,
MovingAverageType movingAverageType = MovingAverageType.Simple)
: this($"ABANDS({period},{width},{movingAverageType})", period, width, movingAverageType)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AccelerationBands" /> class.
/// </summary>
/// <param name="period">The period of the three moving average (middle, upper and lower band).</param>
public AccelerationBands(int period)
: this(period, 4)
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => MiddleBand.IsReady && LowerBand.IsReady && UpperBand.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
base.Reset();
MiddleBand.Reset();
LowerBand.Reset();
UpperBand.Reset();
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>
/// A new value for this indicator
/// </returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
var coefficient = _width * (input.High - input.Low).SafeDivision(input.High + input.Low);
LowerBand.Update(input.EndTime, input.Low * (1 - coefficient));
UpperBand.Update(input.EndTime, input.High * (1 + coefficient));
MiddleBand.Update(input.EndTime, input.Close);
return MiddleBand.Current.Value;
}
}
}
+65
View File
@@ -0,0 +1,65 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the Accumulation/Distribution (AD)
/// The Accumulation/Distribution is calculated using the following formula:
/// AD = AD + ((Close - Low) - (High - Close)) / (High - Low) * Volume
/// </summary>
public class AccumulationDistribution : TradeBarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="AccumulationDistribution"/> class using the specified name.
/// </summary>
public AccumulationDistribution()
: this("AD")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AccumulationDistribution"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public AccumulationDistribution(string name)
: base(name)
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => Samples > 0;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => 1;
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(TradeBar input)
{
var range = input.High - input.Low;
return Current.Value + (range > 0 ? ((input.Close - input.Low) - (input.High - input.Close)) / range * input.Volume : 0m);
}
}
}
@@ -0,0 +1,93 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the Accumulation/Distribution Oscillator (ADOSC)
/// The Accumulation/Distribution Oscillator is calculated using the following formula:
/// ADOSC = EMA(fast,AD) - EMA(slow,AD)
/// </summary>
public class AccumulationDistributionOscillator : TradeBarIndicator, IIndicatorWarmUpPeriodProvider
{
private readonly int _period;
private readonly AccumulationDistribution _ad;
private readonly ExponentialMovingAverage _emaFast;
private readonly ExponentialMovingAverage _emaSlow;
/// <summary>
/// Initializes a new instance of the <see cref="AccumulationDistributionOscillator"/> class using the specified parameters
/// </summary>
/// <param name="fastPeriod">The fast moving average period</param>
/// <param name="slowPeriod">The slow moving average period</param>
public AccumulationDistributionOscillator(int fastPeriod, int slowPeriod)
: this($"ADOSC({fastPeriod},{slowPeriod})", fastPeriod, slowPeriod)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AccumulationDistributionOscillator"/> class using the specified parameters
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="fastPeriod">The fast moving average period</param>
/// <param name="slowPeriod">The slow moving average period</param>
public AccumulationDistributionOscillator(string name, int fastPeriod, int slowPeriod)
: base(name)
{
_period = Math.Max(fastPeriod, slowPeriod);
_ad = new AccumulationDistribution(name + "_AD");
_emaFast = new ExponentialMovingAverage(name + "_Fast", fastPeriod);
_emaSlow = new ExponentialMovingAverage(name + "_Slow", slowPeriod);
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => Samples >= _period;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => _period;
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(TradeBar input)
{
_ad.Update(input);
_emaFast.Update(_ad.Current);
_emaSlow.Update(_ad.Current);
return IsReady ? _emaFast.Current.Value - _emaSlow.Current.Value : 0m;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_ad.Reset();
_emaFast.Reset();
_emaSlow.Reset();
base.Reset();
}
}
}
+32
View File
@@ -0,0 +1,32 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Linq;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Advance Decline Difference compute the difference between the number of stocks
/// that closed higher and the number of stocks that closed lower than their previous day's closing prices.
/// </summary>
public class AdvanceDeclineDifference : AdvanceDeclineIndicator
{
/// <summary>
/// Initializes a new instance of the <see cref="AdvanceDeclineDifference"/> class
/// </summary>
public AdvanceDeclineDifference(string name = "A/D Difference")
: base(name, (entries) => entries.Count(), (advance, decline) => advance - decline) { }
}
}
+186
View File
@@ -0,0 +1,186 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
using System;
using System.Collections.Generic;
using System.Linq;
namespace QuantConnect.Indicators
{
/// <summary>
/// The advance-decline indicator compares the number of stocks
/// that closed higher against the number of stocks
/// that closed lower than their previous day's closing prices.
/// </summary>
public abstract class AdvanceDeclineIndicator : TradeBarIndicator, IIndicatorWarmUpPeriodProvider
{
private IDictionary<SecurityIdentifier, TradeBar> _previousPeriod = new Dictionary<SecurityIdentifier, TradeBar>();
private IDictionary<SecurityIdentifier, TradeBar> _currentPeriod = new Dictionary<SecurityIdentifier, TradeBar>();
private readonly Func<IEnumerable<TradeBar>, decimal> _computeSubValue;
private readonly Func<decimal, decimal, decimal> _computeMainValue;
private DateTime? _currentPeriodTime = null;
/// <summary>
/// Initializes a new instance of the <see cref="AdvanceDeclineRatio"/> class
/// </summary>
public AdvanceDeclineIndicator(string name, Func<IEnumerable<TradeBar>, decimal> computeSub, Func<decimal, decimal, decimal> computeMain)
: base(name)
{
_computeSubValue = computeSub;
_computeMainValue = computeMain;
}
/// <summary>
/// Add tracking asset issue
/// </summary>
/// <param name="asset">tracking asset issue</param>
public virtual void Add(Symbol asset)
{
if (!_currentPeriod.ContainsKey(asset.ID))
{
_currentPeriod.Add(asset.ID, null);
}
}
/// <summary>
/// Deprecated
/// </summary>
[Obsolete("Please use Add(asset)")]
public void AddStock(Symbol asset)
{
Add(asset);
}
/// <summary>
/// Remove tracking asset issue
/// </summary>
/// <param name="asset">tracking asset issue</param>
public virtual void Remove(Symbol asset)
{
_currentPeriod.Remove(asset.ID);
}
/// <summary>
/// Deprecated
/// </summary>
[Obsolete("Please use Remove(asset)")]
public void RemoveStock(Symbol asset)
{
Remove(asset);
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _previousPeriod.Keys.Any();
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => 2;
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(TradeBar input)
{
var advStocks = new List<TradeBar>();
var dclStocks = new List<TradeBar>();
TradeBar tradeBar;
foreach (var stock in _currentPeriod)
{
if (!_previousPeriod.TryGetValue(stock.Key, out tradeBar) || tradeBar == null)
{
continue;
}
else if (stock.Value.Close < tradeBar.Close)
{
dclStocks.Add(stock.Value);
}
else if (stock.Value.Close > tradeBar.Close)
{
advStocks.Add(stock.Value);
}
}
return _computeMainValue(_computeSubValue(advStocks), _computeSubValue(dclStocks));
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override IndicatorResult ValidateAndComputeNextValue(TradeBar input)
{
Enqueue(input);
if (!_previousPeriod.Keys.Any() || _currentPeriod.Any(p => p.Value == null))
{
return new IndicatorResult(0, IndicatorStatus.ValueNotReady);
}
var vNext = ComputeNextValue(input);
return new IndicatorResult(vNext);
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_previousPeriod.Clear();
foreach (var key in _currentPeriod.Keys.ToList())
{
_currentPeriod[key] = null;
}
base.Reset();
}
private void Enqueue(TradeBar input)
{
if (input.EndTime == _currentPeriodTime)
{
_previousPeriod[input.Symbol.ID] = input;
return;
}
if (input.Time > _currentPeriodTime)
{
_previousPeriod.Clear();
foreach (var key in _currentPeriod.Keys.ToList())
{
_previousPeriod[key] = _currentPeriod[key];
_currentPeriod[key] = null;
}
_currentPeriodTime = input.Time;
}
if (_currentPeriod.ContainsKey(input.Symbol.ID) && (!_currentPeriodTime.HasValue || input.Time == _currentPeriodTime))
{
_currentPeriod[input.Symbol.ID] = input;
if (!_currentPeriodTime.HasValue)
{
_currentPeriodTime = input.Time;
}
}
}
}
}
+33
View File
@@ -0,0 +1,33 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Linq;
namespace QuantConnect.Indicators
{
/// <summary>
/// The advance-decline ratio (ADR) compares the number of stocks
/// that closed higher against the number of stocks
/// that closed lower than their previous day's closing prices.
/// </summary>
public class AdvanceDeclineRatio : AdvanceDeclineIndicator
{
/// <summary>
/// Initializes a new instance of the <see cref="AdvanceDeclineRatio"/> class
/// </summary>
public AdvanceDeclineRatio(string name = "A/D Ratio")
: base(name, (entries) => entries.Count(), (advance, decline) => decline == 0m ? advance : advance / decline) { }
}
}
+33
View File
@@ -0,0 +1,33 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Linq;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Advance Decline Volume Ratio is a Breadth indicator calculated as ratio of
/// summary volume of advancing stocks to summary volume of declining stocks.
/// AD Volume Ratio is used in technical analysis to see where the main trading activity is focused.
/// </summary>
public class AdvanceDeclineVolumeRatio : AdvanceDeclineIndicator
{
/// <summary>
/// Initializes a new instance of the <see cref="AdvanceDeclineVolumeRatio"/> class
/// </summary>
public AdvanceDeclineVolumeRatio(string name = "A/D Volume Rate")
: base(name, (entries) => entries.Sum(x => x.Volume), (advance, decline) => decline == 0m ? advance : advance / decline) { }
}
}
+341
View File
@@ -0,0 +1,341 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using Python.Runtime;
using QuantConnect.Data;
using QuantConnect.Data.Market;
using QuantConnect.Python;
using System;
namespace QuantConnect.Indicators
{
/// <summary>
/// In financial analysis, the Alpha indicator is used to measure the performance of an investment (such as a stock or ETF)
/// relative to a benchmark index, often representing the broader market. Alpha indicates the excess return of the investment
/// compared to the return of the benchmark index.
///
/// The S P 500 index is frequently used as a benchmark in Alpha calculations to represent the overall market performance.
/// Alpha is an essential tool for investors to understand the idiosyncratic returns of their investment that aren't caused
/// by movement in the underlying benchmark.
/// </summary>
public class Alpha : BarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Symbol of the reference used
/// </summary>
private readonly Symbol _referenceSymbol;
/// <summary>
/// Symbol of the target used
/// </summary>
private readonly Symbol _targetSymbol;
/// <summary>
/// Period of the indicator - alpha
/// </summary>
private readonly decimal _alphaPeriod;
/// <summary>
/// Rate of change of the target symbol
/// </summary>
private readonly RateOfChange _targetROC;
/// <summary>
/// Rate of change of the reference symbol
/// </summary>
private readonly RateOfChange _referenceROC;
/// <summary>
/// Alpha of the target used in relation with the reference
/// </summary>
private decimal _alpha;
/// <summary>
/// Beta of the target used in relation with the reference
/// </summary>
private readonly Beta _beta;
/// <summary>
/// Interest rate model used to compute the risk free rate
/// </summary>
private readonly IRiskFreeInterestRateModel _riskFreeInterestRateModel;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; private set; }
/// <summary>
/// Gets a flag indicating when the indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _targetROC.IsReady && _beta.IsReady && _referenceROC.IsReady;
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, IRiskFreeInterestRateModel riskFreeRateModel)
: base(name)
{
// Assert that the target and reference symbols are not the same
if (targetSymbol == referenceSymbol)
{
throw new ArgumentException("The target and reference symbols cannot be the same.");
}
// Assert that the period is greater than 2, otherwise the alpha can not be computed
if (alphaPeriod < 1)
{
throw new ArgumentException("The period must be equal or greater than 1.");
}
// Assert that the beta period is greater than 2, otherwise the beta can not be computed
if (betaPeriod < 2)
{
throw new ArgumentException("The beta period must be equal or greater than 2.");
}
_targetSymbol = targetSymbol;
_referenceSymbol = referenceSymbol;
_alphaPeriod = alphaPeriod;
_riskFreeInterestRateModel = riskFreeRateModel;
_targetROC = new RateOfChange($"{name}_TargetROC", alphaPeriod);
_referenceROC = new RateOfChange($"{name}_ReferenceROC", alphaPeriod);
_beta = new Beta($"{name}_Beta", _targetSymbol, _referenceSymbol, betaPeriod);
WarmUpPeriod = alphaPeriod >= betaPeriod ? alphaPeriod + 1 : betaPeriod + 1;
_alpha = 0m;
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRate">The risk free rate of this indicator for given period</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, decimal? riskFreeRate = null)
: this(name, targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period values
/// </summary>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRate">The risk free rate of this indicator for given period</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, decimal? riskFreeRate = null)
: this($"ALPHA({targetSymbol},{referenceSymbol},{alphaPeriod},{betaPeriod},{riskFreeRate})", targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period value
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRate">The risk free rate of this indicator for given period</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int period, decimal? riskFreeRate = null)
: this($"ALPHA({targetSymbol},{referenceSymbol},{period},{riskFreeRate})", targetSymbol, referenceSymbol, period, period, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
/// </summary>
/// <param name="name"></param>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRate">The risk free rate of this indicator for given period</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, decimal? riskFreeRate = null)
: this(name, targetSymbol, referenceSymbol, period, period, new ConstantRiskFreeRateInterestRateModel(riskFreeRate ?? 0m))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period values
/// </summary>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, IRiskFreeInterestRateModel riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{alphaPeriod},{betaPeriod})", targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, riskFreeRateModel)
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period value
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int period, IRiskFreeInterestRateModel riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{period})", targetSymbol, referenceSymbol, period, period, riskFreeRateModel)
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
/// </summary>
/// <param name="name"></param>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, IRiskFreeInterestRateModel riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, period, period, riskFreeRateModel)
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, PyObject riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period values
/// </summary>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="alphaPeriod">Period of the indicator - alpha</param>
/// <param name="betaPeriod">Period of the indicator - beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int alphaPeriod, int betaPeriod, PyObject riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{alphaPeriod},{betaPeriod})", targetSymbol, referenceSymbol, alphaPeriod, betaPeriod, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified target, reference, and period value
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(Symbol targetSymbol, Symbol referenceSymbol, int period, PyObject riskFreeRateModel)
: this($"ALPHA({targetSymbol},{referenceSymbol},{period})", targetSymbol, referenceSymbol, period, period, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
/// <summary>
/// Creates a new Alpha indicator with the specified name, target, reference, and period value
/// </summary>
/// <param name="name"></param>
/// <param name="targetSymbol"></param>
/// <param name="referenceSymbol"></param>
/// <param name="period">Period of the indicator - alpha and beta</param>
/// <param name="riskFreeRateModel">The risk free rate model of this indicator</param>
public Alpha(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, PyObject riskFreeRateModel)
: this(name, targetSymbol, referenceSymbol, period, period, RiskFreeInterestRateModelPythonWrapper.FromPyObject(riskFreeRateModel))
{
}
/// <summary>
/// Computes the next value for this indicator from the given state.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
if (input is null)
{
throw new ArgumentNullException(nameof(input));
}
var inputSymbol = input.Symbol;
if (inputSymbol == _targetSymbol)
{
_targetROC.Update(input.EndTime, input.Close);
}
else if (inputSymbol == _referenceSymbol)
{
_referenceROC.Update(input.EndTime, input.Close);
}
else
{
throw new ArgumentException($"The input symbol {inputSymbol} is not the target or reference symbol.");
}
_beta.Update(input);
if (_targetROC.Samples == _referenceROC.Samples && _referenceROC.Samples > 0)
{
ComputeAlpha();
}
return _alpha;
}
/// <summary>
/// Computes the alpha of the target used in relation with the reference and stores it in the _alpha field
/// </summary>
private void ComputeAlpha()
{
if (!_beta.IsReady || !_targetROC.IsReady || !_referenceROC.IsReady)
{
_alpha = 0m;
return;
}
var targetMean = _targetROC.Current.Value / _alphaPeriod;
var referenceMean = _referenceROC.Current.Value / _alphaPeriod;
var riskFreeRate = _riskFreeInterestRateModel.GetInterestRate(_targetROC.Current.EndTime);
_alpha = targetMean - (riskFreeRate + _beta.Current.Value * (referenceMean - riskFreeRate));
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_targetROC.Reset();
_referenceROC.Reset();
_beta.Reset();
_alpha = 0m;
base.Reset();
}
}
}
+129
View File
@@ -0,0 +1,129 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Arms Index, also called the Short-Term Trading Index (TRIN)
/// is a technical analysis indicator that compares the number of advancing
/// and declining stocks (AD Ratio) to advancing and declining volume (AD volume).
/// </summary>
public class ArmsIndex : TradeBarIndicator, IIndicatorWarmUpPeriodProvider
{
private readonly IndicatorBase<IndicatorDataPoint> _arms;
/// <summary>
/// Gets the Advance/Decline Ratio (ADR) indicator
/// </summary>
public AdvanceDeclineRatio ADRatio { get; }
/// <summary>
/// Gets the Advance/Decline Volume Ratio (ADVR) indicator
/// </summary>
public AdvanceDeclineVolumeRatio ADVRatio { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ArmsIndex"/> class
/// </summary>
public ArmsIndex(string name = "TRIN") : base(name)
{
ADRatio = new AdvanceDeclineRatio(name + "_A/D Ratio");
ADVRatio = new AdvanceDeclineVolumeRatio(name + "_A/D Volume Ratio");
_arms = ADRatio.Over(ADVRatio, name);
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => ADRatio.IsReady && ADVRatio.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => System.Math.Max(ADRatio.WarmUpPeriod, ADVRatio.WarmUpPeriod);
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(TradeBar input)
{
ADRatio.Update(input);
ADVRatio.Update(input);
if (ADVRatio == 0)
{
return 0;
}
return _arms.Current.Value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
ADRatio.Reset();
ADVRatio.Reset();
_arms.Reset();
base.Reset();
}
/// <summary>
/// Add Tracking stock issue
/// </summary>
/// <param name="asset">the tracking stock issue</param>
public void Add(Symbol asset)
{
ADRatio.Add(asset);
ADVRatio.Add(asset);
}
/// <summary>
/// Deprecated
/// </summary>
[Obsolete("Please use Add(asset)")]
public void AddStock(Symbol asset)
{
Add(asset);
}
/// <summary>
/// Remove Tracking stock issue
/// </summary>
/// <param name="asset">the tracking stock issue</param>
public void Remove(Symbol asset)
{
ADRatio.Remove(asset);
ADVRatio.Remove(asset);
}
/// <summary>
/// Deprecated
/// </summary>
[Obsolete("Please use Remove(asset)")]
public void RemoveStock(Symbol asset)
{
Remove(asset);
}
}
}
+120
View File
@@ -0,0 +1,120 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
namespace QuantConnect.Indicators
{
/// <summary>
/// Smooth and high sensitive moving Average. This moving average reduce lag of the information
/// but still being smooth to reduce noises.
/// Is a weighted moving average, which weights have a Normal shape;
/// the parameters Sigma and Offset affect the kurtosis and skewness of the weights respectively.
/// Source: https://www.cjournal.cz/files/308.pdf
/// </summary>
/// <seealso cref="IndicatorDataPoint" />
public class ArnaudLegouxMovingAverage : WindowIndicator<IndicatorDataPoint>, IIndicatorWarmUpPeriodProvider
{
private readonly decimal[] _weightVector;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => _weightVector.Length;
/// <summary>
/// Initializes a new instance of the <see cref="ArnaudLegouxMovingAverage" /> class.
/// </summary>
/// <param name="name">string - a name for the indicator</param>
/// <param name="period">int - the number of periods to calculate the ALMA</param>
/// <param name="sigma">
/// int - this parameter is responsible for the shape of the curve coefficients. It affects the weight vector kurtosis.
/// </param>
/// <param name="offset">
/// decimal - This parameter allows regulating the smoothness and high sensitivity of the
/// Moving Average. The range for this parameter is [0, 1]. It affects the weight vector skewness.
/// </param>
public ArnaudLegouxMovingAverage(string name, int period, int sigma = 6, decimal offset = 0.85m)
: base(name, period)
{
if (offset < 0 || offset > 1) throw new ArgumentException($"Offset parameter range is [0,1]. Value: {offset}", nameof(offset));
var m = Math.Floor(offset * (period - 1));
var s = period * 1m / sigma;
var tmpVector = Enumerable.Range(0, period)
.Select(i => Math.Exp((double) (-(i - m) * (i - m) / (2 * s * s))))
.ToArray();
_weightVector = tmpVector
.Select(i => (decimal) (i / tmpVector.Sum())).Reverse()
.ToArray();
}
/// <summary>
/// Initializes a new instance of the <see cref="ArnaudLegouxMovingAverage" /> class.
/// </summary>
/// <param name="name">string - a name for the indicator</param>
/// <param name="period">int - the number of periods to calculate the ALMA.</param>
public ArnaudLegouxMovingAverage(string name, int period)
: this(name, period, 6)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ArnaudLegouxMovingAverage" /> class.
/// </summary>
/// <param name="period">int - the number of periods to calculate the ALMA</param>
/// <param name="sigma">
/// int - this parameter is responsible for the shape of the curve coefficients. It affects the weight
/// vector kurtosis.
/// </param>
/// <param name="offset">
/// decimal - This parameter allows regulating the smoothness and high sensitivity of the Moving
/// Average. The range for this parameter is [0, 1]. It affects the weight vector skewness.
/// </param>
public ArnaudLegouxMovingAverage(int period, int sigma, decimal offset = 0.85m)
: this($"ALMA({period},{sigma},{offset})", period, sigma, offset)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ArnaudLegouxMovingAverage" /> class.
/// </summary>
/// <param name="period">int - the number of periods to calculate the ALMA.</param>
public ArnaudLegouxMovingAverage(int period)
: this(period, 6)
{
}
/// <summary>
/// Computes the next value for this indicator from the given state.
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input value to this indicator on this time step</param>
/// <returns>
/// A new value for this indicator
/// </returns>
/// <exception cref="System.NotImplementedException"></exception>
protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window,
IndicatorDataPoint input)
{
return IsReady
? window.Select((t, i) => t.Price * _weightVector[i]).Sum()
: input.Value;
}
}
}
+134
View File
@@ -0,0 +1,134 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
using System;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Aroon Oscillator is the difference between AroonUp and AroonDown. The value of this
/// indicator fluctuates between -100 and +100. An upward trend bias is present when the oscillator
/// is positive, and a negative trend bias is present when the oscillator is negative. AroonUp/Down
/// values over 75 identify strong trends in their respective direction.
/// </summary>
public class AroonOscillator : BarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Gets the AroonUp indicator
/// </summary>
public IndicatorBase<IndicatorDataPoint> AroonUp { get; }
/// <summary>
/// Gets the AroonDown indicator
/// </summary>
public IndicatorBase<IndicatorDataPoint> AroonDown { get; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => AroonUp.IsReady && AroonDown.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Creates a new AroonOscillator from the specified up/down periods.
/// </summary>
/// <param name="upPeriod">The lookback period to determine the highest high for the AroonDown</param>
/// <param name="downPeriod">The lookback period to determine the lowest low for the AroonUp</param>
public AroonOscillator(int upPeriod, int downPeriod)
: this($"AROON({upPeriod},{downPeriod})", upPeriod, downPeriod)
{
}
/// <summary>
/// Creates a new AroonOscillator from the specified up/down periods.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="upPeriod">The lookback period to determine the highest high for the AroonDown</param>
/// <param name="downPeriod">The lookback period to determine the lowest low for the AroonUp</param>
public AroonOscillator(string name, int upPeriod, int downPeriod)
: base(name)
{
var max = new Maximum(name + "_Max", upPeriod + 1);
AroonUp = new FunctionalIndicator<IndicatorDataPoint>(name + "_AroonUp",
input => ComputeAroonUp(upPeriod, max, input),
aroonUp => max.IsReady,
() => max.Reset()
);
var min = new Minimum(name + "_Min", downPeriod + 1);
AroonDown = new FunctionalIndicator<IndicatorDataPoint>(name + "_AroonDown",
input => ComputeAroonDown(downPeriod, min, input),
aroonDown => min.IsReady,
() => min.Reset()
);
WarmUpPeriod = 1 + Math.Max(upPeriod, downPeriod);
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
AroonUp.Update(input.EndTime, input.High);
AroonDown.Update(input.EndTime, input.Low);
return AroonUp.Current.Value - AroonDown.Current.Value;
}
/// <summary>
/// AroonUp = 100 * (period - {periods since max})/period
/// </summary>
/// <param name="upPeriod">The AroonUp period</param>
/// <param name="max">A Maximum indicator used to compute periods since max</param>
/// <param name="input">The next input data</param>
/// <returns>The AroonUp value</returns>
private static decimal ComputeAroonUp(int upPeriod, Maximum max, IndicatorDataPoint input)
{
max.Update(input);
return 100m * (upPeriod - max.PeriodsSinceMaximum) / upPeriod;
}
/// <summary>
/// AroonDown = 100 * (period - {periods since min})/period
/// </summary>
/// <param name="downPeriod">The AroonDown period</param>
/// <param name="min">A Minimum indicator used to compute periods since min</param>
/// <param name="input">The next input data</param>
/// <returns>The AroonDown value</returns>
private static decimal ComputeAroonDown(int downPeriod, Minimum min, IndicatorDataPoint input)
{
min.Update(input);
return 100m * (downPeriod - min.PeriodsSinceMinimum) / downPeriod;
}
/// <summary>
/// Resets this indicator and both sub-indicators (AroonUp and AroonDown)
/// </summary>
public override void Reset()
{
AroonUp.Reset();
AroonDown.Reset();
base.Reset();
}
}
}
+122
View File
@@ -0,0 +1,122 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Augen Price Spike indicator is an indicator that measures price
/// changes in terms of standard deviations. In the book, The
/// Volatility Edge in Options Trading, Jeff Augen describes a
/// method for tracking absolute price changes in terms of recent
/// volatility, using the standard deviation.
///
/// length = x
/// closes = closeArray
/// closes1 = closeArray shifted right by 1
/// closes2 = closeArray shifted right by 2
/// closeLog = np.log(np.divide(closes1, closes2))
/// SDev = np.std(closeLog)
/// m = SDev * closes1[-1]
/// spike = (closes[-1]-closes1[-1])/m
/// return spike
///
/// Augen Price Spike from TradingView
/// https://www.tradingview.com/script/fC7Pn2X2-Price-Spike-Jeff-Augen/
///
/// </summary>
public class AugenPriceSpike : Indicator, IIndicatorWarmUpPeriodProvider
{
private readonly StandardDeviation _standardDeviation;
private readonly RollingWindow<decimal> _rollingData;
/// <summary>
/// Initializes a new instance of the AugenPriceSpike class using the specified period
/// </summary>
/// <param name="period">The period over which to perform to computation</param>
public AugenPriceSpike(int period = 3)
: this($"APS({period})", period)
{
}
/// <summary>
/// Creates a new AugenPriceSpike indicator with the specified period
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of this indicator</param>
public AugenPriceSpike(string name, int period)
: base(name)
{
if (period < 3)
{
throw new ArgumentException("AugenPriceSpike Indicator must have a period of at least 3", nameof(period));
}
_standardDeviation = new StandardDeviation(period);
_rollingData = new RollingWindow<decimal>(3);
WarmUpPeriod = period + 2;
}
/// <summary>
/// Gets a flag indicating when the indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _rollingData.IsReady && _standardDeviation.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Computes the next value for this indicator from the given state.
/// </summary>
/// <param name="input">The input value to this indicator on this time step</param>
/// <returns>A a value for this indicator</returns>
protected override decimal ComputeNextValue(IndicatorDataPoint input)
{
_rollingData.Add(input.Value);
if (_rollingData.Count < 3) { return 0m; }
var previousPoint = _rollingData[1];
var previousPoint2 = _rollingData[2];
var logPoint = 0.0;
// Ensure the logarithm operation is valid, as log(0) is undefined, and avoid division by zero.
if (previousPoint != 0 && previousPoint2 != 0)
{
logPoint = Math.Log((double)previousPoint / (double)previousPoint2);
}
_standardDeviation.Update(input.EndTime, (decimal)logPoint);
if (!_rollingData.IsReady) { return 0m; }
if (!_standardDeviation.IsReady) { return 0m; }
var m = _standardDeviation.Current.Value * previousPoint;
if (m == 0) { return 0; }
var spikeValue = (input.Value - previousPoint) / m;
return spikeValue;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_standardDeviation.Reset();
_rollingData.Reset();
base.Reset();
}
}
}
@@ -0,0 +1,395 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using MathNet.Numerics;
using MathNet.Numerics.LinearAlgebra.Double;
using MathNet.Numerics.LinearRegression;
namespace QuantConnect.Indicators
{
/// <summary>
/// An Autoregressive Intergrated Moving Average (ARIMA) is a time series model which can be used to describe a set of data.
/// In particular,with Xₜ representing the series, the model assumes the data are of form
/// (after differencing <see cref="_diffOrder" /> times):
/// <para>
/// Xₜ = c + εₜ + ΣᵢφᵢXₜ₋ᵢ + Σᵢθᵢεₜ₋ᵢ
/// </para>
/// where the first sum has an upper limit of <see cref="_arOrder" /> and the second <see cref="_maOrder" />.
/// </summary>
public class AutoRegressiveIntegratedMovingAverage : TimeSeriesIndicator
{
private List<double> _residuals;
private readonly bool _intercept;
private bool _loggedOnceInMovingAverageStep;
private bool _loggedOnceInAutoRegressiveStep;
private readonly RollingWindow<double> _rollingData;
/// <summary>
/// Differencing coefficient (d). Determines how many times the series should be differenced before fitting the
/// model.
/// </summary>
private readonly int _diffOrder;
/// <summary>
/// AR coefficient -- p
/// </summary>
private readonly int _arOrder;
/// <summary>
/// MA Coefficient -- q
/// </summary>
private readonly int _maOrder;
/// <summary>
/// Whether or not to handle potential exceptions, returning a zero value. I.e, the values
/// provided as input are not valid by the Normal Equations direct regression method
/// </summary>
public bool HandleExceptions { get; set; } = true;
/// <summary>
/// Fitted AR parameters (φ terms).
/// </summary>
public double[] ArParameters { get; private set; }
/// <summary>
/// Fitted MA parameters (θ terms).
/// </summary>
public double[] MaParameters { get; private set; }
/// <summary>
/// Fitted intercept (c term).
/// </summary>
public double Intercept { get; private set; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _rollingData.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public override int WarmUpPeriod { get; }
/// <summary>
/// The variance of the residuals (Var(ε)) from the first step of <see cref="TwoStepFit" />.
/// </summary>
public double ArResidualError { get; private set; }
/// <summary>
/// The variance of the residuals (Var(ε)) from the second step of <see cref="TwoStepFit" />.
/// </summary>
public double MaResidualError { get; private set; }
/// <summary>
/// Fits an ARIMA(arOrder,diffOrder,maOrder) model of form (after differencing it <see cref="_diffOrder" /> times):
/// <para>
/// Xₜ = c + εₜ + ΣᵢφᵢXₜ₋ᵢ + Σᵢθᵢεₜ₋ᵢ
/// </para>
/// where the first sum has an upper limit of <see cref="_arOrder" /> and the second <see cref="_maOrder" />.
/// This particular constructor fits the model by means of <see cref="TwoStepFit" /> for a specified name.
/// </summary>
/// <param name="name">The name of the indicator</param>
/// <param name="arOrder">AR order (p) -- defines the number of past values to consider in the AR component of the model.</param>
/// <param name="diffOrder">Difference order (d) -- defines how many times to difference the model before fitting parameters.</param>
/// <param name="maOrder">MA order -- defines the number of past values to consider in the MA component of the model.</param>
/// <param name="period">Size of the rolling series to fit onto</param>
/// <param name="intercept">Whether or not to include the intercept term</param>
public AutoRegressiveIntegratedMovingAverage(
string name,
int arOrder,
int diffOrder,
int maOrder,
int period,
bool intercept = true
)
: base(name)
{
if (arOrder < 0 || maOrder < 0)
{
throw new ArgumentException("AR/MA orders cannot be negative.");
}
if (arOrder == 0)
{
throw new ArgumentException("arOrder (p) must be greater than zero for all " +
"currently available fitting methods.");
}
if (period < Math.Max(arOrder, maOrder))
{
throw new ArgumentException("Period must exceed both arOrder and maOrder");
}
_arOrder = arOrder;
_maOrder = maOrder;
_diffOrder = diffOrder;
WarmUpPeriod = period;
_rollingData = new RollingWindow<double>(period);
_intercept = intercept;
}
/// <summary>
/// Fits an ARIMA(arOrder,diffOrder,maOrder) model of form (after differencing it <see cref="_diffOrder" /> times):
/// <para>
/// Xₜ = c + εₜ + ΣᵢφᵢXₜ₋ᵢ + Σᵢθᵢεₜ₋ᵢ
/// </para>
/// where the first sum has an upper limit of <see cref="_arOrder" /> and the second <see cref="_maOrder" />.
/// This particular constructor fits the model by means of <see cref="TwoStepFit" /> using ordinary least squares.
/// </summary>
/// <param name="arOrder">AR order (p) -- defines the number of past values to consider in the AR component of the model.</param>
/// <param name="diffOrder">Difference order (d) -- defines how many times to difference the model before fitting parameters.</param>
/// <param name="maOrder">MA order (q) -- defines the number of past values to consider in the MA component of the model.</param>
/// <param name="period">Size of the rolling series to fit onto</param>
/// <param name="intercept">Whether to include an intercept term (c)</param>
public AutoRegressiveIntegratedMovingAverage(
int arOrder,
int diffOrder,
int maOrder,
int period,
bool intercept
)
: this($"ARIMA(({arOrder}, {diffOrder}, {maOrder}), {period}, {intercept})", arOrder, diffOrder, maOrder,
period, intercept)
{
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
base.Reset();
_rollingData.Reset();
}
/// <summary>
/// Forecasts the series of the fitted model one point ahead.
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IndicatorDataPoint input)
{
_rollingData.Add((double)input.Value);
if (_rollingData.IsReady)
{
var arrayData = _rollingData.ToArray();
double[] diffHeads = default;
arrayData = _diffOrder > 0 ? DifferenceSeries(_diffOrder, arrayData, out diffHeads) : arrayData;
_diffHeads = diffHeads;
TwoStepFit(arrayData);
double summants = 0;
if (_arOrder > 0)
{
for (var i = 0; i < _arOrder; i++) // AR Parameters
{
summants += ArParameters[i] * arrayData[i];
}
}
if (_maOrder > 0)
{
for (var i = 0; i < _maOrder; i++) // MA Parameters
{
summants += MaParameters[i] * _residuals[_maOrder + i + 1];
}
}
summants += Intercept; // By default equals 0
if (_diffOrder > 0)
{
var dataCast = arrayData.ToList();
dataCast.Insert(0, summants); // Prepends
summants = InverseDifferencedSeries(dataCast.ToArray(), _diffHeads).First(); // Returns disintegrated series
}
return (decimal)summants;
}
return 0m;
}
/// <summary>
/// Fits the model by means of implementing the following pseudo-code algorithm (in the form of "if{then}"):
/// <code>
/// if diffOrder > 0 {Difference data diffOrder times}
/// if arOrder > 0 {Fit the AR model Xₜ = ΣᵢφᵢXₜ; ε's are set to residuals from fitting this.}
/// if maOrder > 0 {Fit the MA parameters left over Xₜ = c + εₜ + ΣᵢφᵢXₜ₋ᵢ + Σᵢθᵢεₜ₋ᵢ}
/// Return: φ and θ estimates.
/// </code>
/// http://mbhauser.com/informal-notes/two-step-arma-estimation.pdf
/// </summary>
private void TwoStepFit(double[] series) // Protected for any future inheritors (e.g., SARIMA)
{
_residuals = new List<double>();
double errorAr = 0;
double errorMa = 0;
var lags = _arOrder > 0 ? LaggedSeries(_arOrder, series) : new[] {series};
AutoRegressiveStep(lags, series, errorAr);
if (_maOrder <= 0)
{
return;
}
MovingAverageStep(lags, series, errorMa);
}
/// <summary>
/// Fits the moving average component in the <see cref="TwoStepFit"/> method.
/// </summary>
/// <param name="lags">An array of lagged data (<see cref="TimeSeriesIndicator.LaggedSeries"/>).</param>
/// <param name="data">The input series, differenced <see cref="_diffOrder"/> times.</param>
/// <param name="errorMa">The summed residuals (by default 0) associated with the MA component.</param>
private void MovingAverageStep(double[][] lags, double[] data, double errorMa)
{
var appendedData = new List<double[]>();
var laggedErrors = LaggedSeries(_maOrder, _residuals.ToArray());
for (var i = 0; i < laggedErrors.Length; i++)
{
var doubles = lags[i].ToList();
doubles.AddRange(laggedErrors[i]);
appendedData.Add(doubles.ToArray());
}
double[] maFits = default;
if (HandleExceptions)
{
try
{
maFits = Fit.MultiDim(appendedData.ToArray(), data.Skip(_maOrder).ToArray(),
method: DirectRegressionMethod.NormalEquations, intercept: _intercept);
}
catch (Exception ex)
{
if (!_loggedOnceInMovingAverageStep)
{
Logging.Log.Error($"AutoRegressiveIntegratedMovingAverage.MovingAverageStep(): {ex.Message}");
_loggedOnceInMovingAverageStep = true;
}
// The method Fit.MultiDim takes the appendedData array of mxn(m rows, n columns), computes its
// transpose of size nxm, and then multiplies the tranpose with the original matrix, so the
// resultant matrix is of size nxn. Then a linear system Ax=b is solved where A is the
// aforementioned matrix and b is the data. Thus, the size of the response x is n
//
// It's worth saying that if intercept flag is set to true, the number of columns of the initial
// matrix (appendedData) is increased in one. For more information, please see the implementation
// of Fit.MultiDim() method (Ctrl + right click)
var size = appendedData.ToArray()[0].Length + (_intercept ? 1 : 0);
maFits = new double[size];
}
}
else
{
maFits = Fit.MultiDim(appendedData.ToArray(), data.Skip(_maOrder).ToArray(),
method: DirectRegressionMethod.NormalEquations, intercept: _intercept);
}
for (var i = _maOrder; i < data.Length; i++) // Calculate the error assoc. with model.
{
var paramVector = _intercept
? Vector.Build.Dense(maFits.Skip(1).ToArray())
: Vector.Build.Dense(maFits);
var residual = data[i] - Vector.Build.Dense(appendedData[i - _maOrder]).DotProduct(paramVector);
errorMa += Math.Pow(residual, 2);
}
switch (_intercept)
{
case true:
MaResidualError = errorMa / (data.Length - Math.Max(_arOrder, _maOrder) - 1);
MaParameters = maFits.Skip(1 + _arOrder).ToArray();
ArParameters = maFits.Skip(1).Take(_arOrder).ToArray();
Intercept = maFits[0];
break;
default:
MaResidualError = errorMa / (data.Length - Math.Max(_arOrder, _maOrder) - 1);
MaParameters = maFits.Skip(_arOrder).ToArray();
ArParameters = maFits.Take(_arOrder).ToArray();
break;
}
}
/// <summary>
/// Fits the autoregressive component in the <see cref="TwoStepFit"/> method.
/// </summary>
/// <param name="lags">An array of lagged data (<see cref="TimeSeriesIndicator.LaggedSeries"/>).</param>
/// <param name="data">The input series, differenced <see cref="_diffOrder"/> times.</param>
/// <param name="errorAr">The summed residuals (by default 0) associated with the AR component.</param>
private void AutoRegressiveStep(double[][] lags, double[] data, double errorAr)
{
double[] arFits;
if (HandleExceptions)
{
try
{
// The function (lags[time][lagged X]) |---> ΣᵢφᵢXₜ₋ᵢ
arFits = Fit.MultiDim(lags, data.Skip(_arOrder).ToArray(),
method: DirectRegressionMethod.NormalEquations);
}
catch (Exception ex)
{
if (!_loggedOnceInAutoRegressiveStep)
{
Logging.Log.Error($"AutoRegressiveIntegratedMovingAverage.AutoRegressiveStep(): {ex.Message}");
_loggedOnceInAutoRegressiveStep = true;
}
// The method Fit.MultiDim takes the lags array of mxn(m rows, n columns), computes its
// transpose of size nxm, and then multiplies the tranpose with the original matrix, so the
// resultant matrix is of size nxn. Then a linear system Ax=b is solved where A is the
// aforementioned matrix and b is the data. Thus, the size of the response x is n
//
// For more information, please see the implementation of Fit.MultiDim() method (Ctrl + right click)
var size = lags.ToArray()[0].Length;
arFits = new double[size];
}
}
else
{
// The function (lags[time][lagged X]) |---> ΣᵢφᵢXₜ₋ᵢ
arFits = Fit.MultiDim(lags, data.Skip(_arOrder).ToArray(),
method: DirectRegressionMethod.NormalEquations);
}
var fittedVec = Vector.Build.Dense(arFits);
for (var i = 0; i < data.Length; i++) // Calculate the error assoc. with model.
{
if (i < _arOrder)
{
_residuals.Add(0); // 0-padding
continue;
}
var residual = data[i] - Vector.Build.Dense(lags[i - _arOrder]).DotProduct(fittedVec);
errorAr += Math.Pow(residual, 2);
_residuals.Add(residual);
}
ArResidualError = errorAr / (data.Length - _arOrder - 1);
if (_maOrder == 0)
{
ArParameters = arFits; // Will not be thrown out
}
}
}
}
+264
View File
@@ -0,0 +1,264 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes Average Directional Index which measures trend strength without regard to trend direction.
/// Firstly, it calculates the Directional Movement and the True Range value, and then the values are accumulated and smoothed
/// using a custom smoothing method proposed by Wilder. For an n period smoothing, 1/n of each period's value is added to the total period.
/// From these accumulated values we are therefore able to derived the 'Positive Directional Index' (+DI) and 'Negative Directional Index' (-DI)
/// which is used to calculate the Average Directional Index.
/// Computation source:
/// https://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:average_directional_index_adx
/// </summary>
public class AverageDirectionalIndex : BarIndicator, IIndicatorWarmUpPeriodProvider
{
private readonly int _period;
private readonly IndicatorBase<IBaseDataBar> _trueRange;
private readonly IndicatorBase<IBaseDataBar> _directionalMovementPlus;
private readonly IndicatorBase<IBaseDataBar> _directionalMovementMinus;
private readonly IndicatorBase<IndicatorDataPoint> _smoothedTrueRange;
private readonly IndicatorBase<IndicatorDataPoint> _smoothedDirectionalMovementPlus;
private readonly IndicatorBase<IndicatorDataPoint> _smoothedDirectionalMovementMinus;
private readonly IndicatorBase<IndicatorDataPoint> _averageDirectionalIndex;
private IBaseDataBar _previousInput;
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _averageDirectionalIndex.IsReady;
/// <summary>
/// Gets the index of the Plus Directional Indicator
/// </summary>
/// <value>
/// The index of the Plus Directional Indicator.
/// </value>
public IndicatorBase<IndicatorDataPoint> PositiveDirectionalIndex { get; }
/// <summary>
/// Gets the index of the Minus Directional Indicator
/// </summary>
/// <value>
/// The index of the Minus Directional Indicator.
/// </value>
public IndicatorBase<IndicatorDataPoint> NegativeDirectionalIndex { get; }
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => _period * 2;
/// <summary>
/// Initializes a new instance of the <see cref="AverageDirectionalIndex"/> class.
/// </summary>
/// <param name="period">The period.</param>
public AverageDirectionalIndex(int period)
: this($"ADX({period})", period)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AverageDirectionalIndex"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="period">The period.</param>
public AverageDirectionalIndex(string name, int period)
: base(name)
{
_period = period;
_trueRange = new FunctionalIndicator<IBaseDataBar>(name + "_TrueRange",
ComputeTrueRange,
isReady => _previousInput != null
);
_directionalMovementPlus = new FunctionalIndicator<IBaseDataBar>(name + "_PositiveDirectionalMovement",
ComputePositiveDirectionalMovement,
isReady => _previousInput != null
);
_directionalMovementMinus = new FunctionalIndicator<IBaseDataBar>(name + "_NegativeDirectionalMovement",
ComputeNegativeDirectionalMovement,
isReady => _previousInput != null
);
PositiveDirectionalIndex = new FunctionalIndicator<IndicatorDataPoint>(name + "_PositiveDirectionalIndex",
input =>
{
// Computes the Plus Directional Indicator(+DI period).
if (_smoothedTrueRange != 0 && _smoothedDirectionalMovementPlus.IsReady)
{
return 100m * _smoothedDirectionalMovementPlus.Current.Value / _smoothedTrueRange.Current.Value;
}
return 0m;
},
positiveDirectionalIndex => _smoothedDirectionalMovementPlus.IsReady,
() =>
{
_directionalMovementPlus.Reset();
_trueRange.Reset();
}
);
NegativeDirectionalIndex = new FunctionalIndicator<IndicatorDataPoint>(name + "_NegativeDirectionalIndex",
input =>
{
// Computes the Minus Directional Indicator(-DI period).
if (_smoothedTrueRange != 0 && _smoothedDirectionalMovementMinus.IsReady)
{
return 100m * _smoothedDirectionalMovementMinus.Current.Value / _smoothedTrueRange.Current.Value;
}
return 0m;
},
negativeDirectionalIndex => _smoothedDirectionalMovementMinus.IsReady,
() =>
{
_directionalMovementMinus.Reset();
_trueRange.Reset();
}
);
_smoothedTrueRange = new FunctionalIndicator<IndicatorDataPoint>(name + "_SmoothedTrueRange",
input =>
{
// Computes the Smoothed True Range value.
var value = Samples > _period + 1 ? _smoothedTrueRange.Current.Value / _period : 0m;
return _smoothedTrueRange.Current.Value + _trueRange.Current.Value - value;
},
isReady => Samples > period
);
_smoothedDirectionalMovementPlus = new FunctionalIndicator<IndicatorDataPoint>(name + "_SmoothedDirectionalMovementPlus",
input =>
{
// Computes the Smoothed Directional Movement Plus value.
var value = Samples > _period + 1 ? _smoothedDirectionalMovementPlus.Current.Value / _period : 0m;
return _smoothedDirectionalMovementPlus.Current.Value + _directionalMovementPlus.Current.Value - value;
},
isReady => Samples > period
);
_smoothedDirectionalMovementMinus = new FunctionalIndicator<IndicatorDataPoint>(name + "_SmoothedDirectionalMovementMinus",
input =>
{
// Computes the Smoothed Directional Movement Minus value.
var value = Samples > _period + 1 ? _smoothedDirectionalMovementMinus.Current.Value / _period : 0m;
return _smoothedDirectionalMovementMinus.Current.Value + _directionalMovementMinus.Current.Value - value;
},
isReady => Samples > period
);
_averageDirectionalIndex = new WilderMovingAverage(period);
}
/// <summary>
/// Computes the True Range value.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
private decimal ComputeTrueRange(IBaseDataBar input)
{
if (_previousInput == null) return 0m;
var range1 = input.High - input.Low;
var range2 = Math.Abs(input.High - _previousInput.Close);
var range3 = Math.Abs(input.Low - _previousInput.Close);
return Math.Max(range1, Math.Max(range2, range3));
}
/// <summary>
/// Computes the positive directional movement.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
private decimal ComputePositiveDirectionalMovement(IBaseDataBar input)
{
if (_previousInput != null &&
input.High > _previousInput.High &&
input.High - _previousInput.High >= _previousInput.Low - input.Low)
{
return input.High - _previousInput.High;
}
return 0m;
}
/// <summary>
/// Computes the negative directional movement.
/// </summary>
/// <param name="input">The input.</param>
/// <returns></returns>
private decimal ComputeNegativeDirectionalMovement(IBaseDataBar input)
{
if (_previousInput != null &&
_previousInput.Low > input.Low &&
_previousInput.Low - input.Low > input.High - _previousInput.High)
{
return _previousInput.Low - input.Low;
}
return 0m;
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
_trueRange.Update(input);
_directionalMovementPlus.Update(input);
_directionalMovementMinus.Update(input);
_smoothedTrueRange.Update(Current);
_smoothedDirectionalMovementPlus.Update(Current);
_smoothedDirectionalMovementMinus.Update(Current);
_previousInput = input;
PositiveDirectionalIndex.Update(Current);
NegativeDirectionalIndex.Update(Current);
var diff = Math.Abs(PositiveDirectionalIndex.Current.Value - NegativeDirectionalIndex.Current.Value);
var sum = PositiveDirectionalIndex.Current.Value + NegativeDirectionalIndex.Current.Value;
if (sum == 0) return 50m;
_averageDirectionalIndex.Update(input.EndTime, 100m * diff / sum);
return _averageDirectionalIndex.Current.Value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
base.Reset();
_previousInput = null;
_trueRange.Reset();
_directionalMovementPlus.Reset();
_directionalMovementMinus.Reset();
_smoothedTrueRange.Reset();
_smoothedDirectionalMovementPlus.Reset();
_smoothedDirectionalMovementMinus.Reset();
_averageDirectionalIndex.Reset();
PositiveDirectionalIndex.Reset();
NegativeDirectionalIndex.Reset();
}
}
}
@@ -0,0 +1,94 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the Average Directional Movement Index Rating (ADXR).
/// The Average Directional Movement Index Rating is calculated with the following formula:
/// ADXR[i] = (ADX[i] + ADX[i - period + 1]) / 2
/// </summary>
public class AverageDirectionalMovementIndexRating : BarIndicator, IIndicatorWarmUpPeriodProvider
{
private readonly int _period;
private readonly RollingWindow<decimal> _adxHistory;
/// <summary>
/// Initializes a new instance of the <see cref="AverageDirectionalMovementIndexRating"/> class using the specified name and period.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of the ADXR</param>
public AverageDirectionalMovementIndexRating(string name, int period)
: base(name)
{
_period = period;
ADX = new AverageDirectionalIndex(name + "_ADX", period);
_adxHistory = new RollingWindow<decimal>(period);
}
/// <summary>
/// Initializes a new instance of the <see cref="AverageDirectionalMovementIndexRating"/> class using the specified period.
/// </summary>
/// <param name="period">The period of the ADXR</param>
public AverageDirectionalMovementIndexRating(int period)
: this($"ADXR({period})", period)
{
}
/// <summary>
/// The Average Directional Index indicator instance being used
/// </summary>
public AverageDirectionalIndex ADX { get; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _adxHistory.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => _period * 3 - 1;
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
ADX.Update(input);
if (ADX.IsReady)
{
_adxHistory.Add(ADX.Current.Value);
}
return IsReady ? (ADX.Current.Value + _adxHistory[_period - 1]) / 2 : 50m;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
ADX.Reset();
_adxHistory.Reset();
base.Reset();
}
}
}
+81
View File
@@ -0,0 +1,81 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// Represents the Average Range (AR) indicator, which calculates the average price range
/// </summary>
public class AverageRange : BarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// The Simple Moving Average (SMA) used to calculate the average of the price ranges.
/// </summary>
private readonly SimpleMovingAverage _sma;
/// <summary>
/// Initializes a new instance of the AverageRange class with the specified name and period.
/// </summary>
/// <param name="name">The name of the AR indicator.</param>
/// <param name="period">The number of periods over which to compute the average range.</param>
public AverageRange(string name, int period) : base(name)
{
_sma = new SimpleMovingAverage(name + "_SMA", period);
}
/// <summary>
/// Initializes the AR indicator with the default name format and period.
/// </summary>
public AverageRange(int period)
: this($"AR({period})", period)
{
}
/// <summary>
/// Indicates whether the indicator has enough data to start producing valid results.
/// </summary>
public override bool IsReady => _sma.IsReady;
/// <summary>
/// The number of periods needed to fully initialize the AR indicator.
/// </summary>
public int WarmUpPeriod => _sma.WarmUpPeriod;
/// <summary>
/// Resets the indicator and clears the internal state, including the SMA.
/// </summary>
public override void Reset()
{
_sma.Reset();
base.Reset();
}
/// <summary>
/// Computes the next value of the Average Range (AR) by calculating the price range (high - low)
/// and passing it to the SMA to get the smoothed value.
/// </summary>
/// <param name="input">The input data for the current bar, including open, high, low, close values.</param>
/// <returns>The computed AR value, which is the smoothed average of price ranges.</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
var priceRange = input.High - input.Low;
// Update the SMA with the price range
_sma.Update(new IndicatorDataPoint(input.EndTime, priceRange));
return _sma.Current.Value;
}
}
}
+100
View File
@@ -0,0 +1,100 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// The AverageTrueRange indicator is a measure of volatility introduced by Welles Wilder in his
/// book: New Concepts in Technical Trading Systems. This indicator computes the TrueRange and then
/// smoothes the TrueRange over a given period.
///
/// TrueRange is defined as the maximum of the following:
/// High - Low
/// ABS(High - PreviousClose)
/// ABS(Low - PreviousClose)
/// </summary>
public class AverageTrueRange : BarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>This indicator is used to smooth the TrueRange computation</summary>
/// <remarks>This is not exposed publicly since it is the same value as this indicator, meaning
/// that this '_smoother' computers the ATR directly, so exposing it publicly would be duplication</remarks>
private readonly IndicatorBase<IndicatorDataPoint> _smoother;
/// <summary>
/// Gets the true range which is the more volatile calculation to be smoothed by this indicator
/// </summary>
public IndicatorBase<IBaseDataBar> TrueRange { get; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _smoother.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Creates a new AverageTrueRange indicator using the specified period and moving average type
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The smoothing period used to smooth the true range values</param>
/// <param name="movingAverageType">The type of smoothing used to smooth the true range values</param>
public AverageTrueRange(string name, int period, MovingAverageType movingAverageType = MovingAverageType.Wilders)
: base(name)
{
WarmUpPeriod = period;
TrueRange = new TrueRange(name);
_smoother = movingAverageType.AsIndicator($"{name}_{movingAverageType}", period).Of(TrueRange, false);
}
/// <summary>
/// Creates a new AverageTrueRange indicator using the specified period and moving average type
/// </summary>
/// <param name="period">The smoothing period used to smooth the true range values</param>
/// <param name="movingAverageType">The type of smoothing used to smooth the true range values</param>
public AverageTrueRange(int period, MovingAverageType movingAverageType = MovingAverageType.Wilders)
: this($"ATR({period})", period, movingAverageType)
{
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
// compute the true range and then send it to our smoother
TrueRange.Update(input);
return _smoother.Current.Value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_smoother.Reset();
TrueRange.Reset();
base.Reset();
}
}
}
+101
View File
@@ -0,0 +1,101 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
using System;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Awesome Oscillator Indicator tracks the price midpoint-movement of a security. Specifically,
/// <para>
/// AO = MAfast[(H+L)/2] - MAslow[(H+L)/2]
/// </para>
/// where MAfast and MAslow denote simple moving averages wherein fast has a shorter period.
/// https://www.barchart.com/education/technical-indicators/awesome_oscillator
/// </summary>
public class AwesomeOscillator : BarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Gets the indicators slow period moving average.
/// </summary>
public IndicatorBase<IndicatorDataPoint> SlowAo { get; }
/// <summary>
/// Gets the indicators fast period moving average.
/// </summary>
public IndicatorBase<IndicatorDataPoint> FastAo { get; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => SlowAo.IsReady && FastAo.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Creates a new Awesome Oscillator from the specified periods.
/// </summary>
/// <param name="fastPeriod">The period of the fast moving average associated with the AO</param>
/// <param name="slowPeriod">The period of the slow moving average associated with the AO</param>
/// <param name="type">The type of moving average used when computing the fast and slow term. Defaults to simple moving average.</param>
public AwesomeOscillator(int fastPeriod, int slowPeriod, MovingAverageType type = MovingAverageType.Simple)
: this($"AO({fastPeriod},{slowPeriod},{type})", fastPeriod, slowPeriod, type)
{
}
/// <summary>
/// Creates a new Awesome Oscillator from the specified periods.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="fastPeriod">The period of the fast moving average associated with the AO</param>
/// <param name="slowPeriod">The period of the slow moving average associated with the AO</param>
/// <param name="type">The type of moving average used when computing the fast and slow term. Defaults to simple moving average.</param>
public AwesomeOscillator(string name, int fastPeriod, int slowPeriod, MovingAverageType type = MovingAverageType.Simple)
: base(name)
{
SlowAo = type.AsIndicator(slowPeriod);
FastAo = type.AsIndicator(fastPeriod);
WarmUpPeriod = Math.Max(slowPeriod, fastPeriod);
}
/// <summary>
/// Computes the next value of this indicator from the given state.
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
var presentValue = (input.High + input.Low) / 2;
SlowAo.Update(input.EndTime, presentValue);
FastAo.Update(input.EndTime, presentValue);
return IsReady ? FastAo - SlowAo : 0m;
}
/// <summary>
/// Resets this indicator
/// </summary>
public override void Reset()
{
FastAo.Reset();
SlowAo.Reset();
base.Reset();
}
}
}
+65
View File
@@ -0,0 +1,65 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the Balance Of Power (BOP).
/// The Balance Of Power is calculated with the following formula:
/// BOP = (Close - Open) / (High - Low)
/// </summary>
public class BalanceOfPower : BarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Initializes a new instance of the <see cref="BalanceOfPower"/> class using the specified name.
/// </summary>
public BalanceOfPower()
: this("BOP")
{
}
/// <summary>
/// Initializes a new instance of the <see cref="BalanceOfPower"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public BalanceOfPower(string name)
: base(name)
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => Samples > 0;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => 1;
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
var range = input.High - input.Low;
return range > 0 ? (input.Close - input.Open) / range : 0m;
}
}
}
+36
View File
@@ -0,0 +1,36 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// The BarIndicator is an indicator that accepts IBaseDataBar data as its input.
///
/// This type is more of a shim/typedef to reduce the need to refer to things as IndicatorBase&lt;IBaseDataBar&gt;
/// </summary>
public abstract class BarIndicator : IndicatorBase<IBaseDataBar>
{
/// <summary>
/// Creates a new TradeBarIndicator with the specified name
/// </summary>
/// <param name="name">The name of this indicator</param>
protected BarIndicator(string name)
: base(name)
{
}
}
}
+144
View File
@@ -0,0 +1,144 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
using MathNet.Numerics.Statistics;
namespace QuantConnect.Indicators
{
/// <summary>
/// In technical analysis Beta indicator is used to measure volatility or risk of a target (ETF) relative to the overall
/// risk (volatility) of the reference (market indexes). The Beta indicators compares target's price movement to the
/// movements of the indexes over the same period of time.
///
/// It is common practice to use the SPX index as a benchmark of the overall reference market when it comes to Beta
/// calculations.
///
/// The indicator only updates when both assets have a price for a time step. When a bar is missing for one of the assets,
/// the indicator value fills forward to improve the accuracy of the indicator.
/// </summary>
public class Beta : DualSymbolIndicator<IBaseDataBar>
{
/// <summary>
/// RollingWindow of returns of the target symbol in the given period
/// </summary>
private readonly RollingWindow<double> _targetReturns;
/// <summary>
/// RollingWindow of returns of the reference symbol in the given period
/// </summary>
private readonly RollingWindow<double> _referenceReturns;
/// <summary>
/// Gets a flag indicating when the indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _targetReturns.IsReady && _referenceReturns.IsReady;
/// <summary>
/// Creates a new Beta indicator with the specified name, target, reference,
/// and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
public Beta(string name, Symbol targetSymbol, Symbol referenceSymbol, int period)
: base(name, targetSymbol, referenceSymbol, 2)
{
// Assert the period is greater than two, otherwise the beta can not be computed
if (period < 2)
{
throw new ArgumentException($"Period parameter for Beta indicator must be greater than 2 but was {period}.");
}
_targetReturns = new RollingWindow<double>(period);
_referenceReturns = new RollingWindow<double>(period);
WarmUpPeriod += (period - 2) + 1;
}
/// <summary>
/// Creates a new Beta indicator with the specified target, reference,
/// and period values
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
public Beta(Symbol targetSymbol, Symbol referenceSymbol, int period)
: this($"B({period})", targetSymbol, referenceSymbol, period)
{
}
/// <summary>
/// Creates a new Beta indicator with the specified name, period, target and
/// reference values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <remarks>Constructor overload for backward compatibility.</remarks>
public Beta(string name, int period, Symbol targetSymbol, Symbol referenceSymbol)
: this(name, targetSymbol, referenceSymbol, period)
{
}
/// <summary>
/// Computes the returns with the new given data point and the last given data point
/// </summary>
/// <param name="rollingWindow">The collection of data points from which we want
/// to compute the return</param>
/// <returns>The returns with the new given data point</returns>
private static double GetNewReturn(IReadOnlyWindow<IBaseDataBar> rollingWindow)
{
return (double)(rollingWindow[0].Close.SafeDivision(rollingWindow[1].Close) - 1);
}
/// <summary>
/// Computes the beta value of the target in relation with the reference
/// using the target and reference returns
/// </summary>
protected override decimal ComputeIndicator()
{
if (TargetDataPoints.IsReady)
{
_targetReturns.Add(GetNewReturn(TargetDataPoints));
}
if (ReferenceDataPoints.IsReady)
{
_referenceReturns.Add(GetNewReturn(ReferenceDataPoints));
}
var varianceComputed = _referenceReturns.Variance();
var covarianceComputed = _targetReturns.Covariance(_referenceReturns);
// Avoid division with NaN or by zero
var variance = !varianceComputed.IsNaNOrZero() ? varianceComputed : 1;
var covariance = !covarianceComputed.IsNaNOrZero() ? covarianceComputed : 0;
return (decimal)(covariance / variance);
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_targetReturns.Reset();
_referenceReturns.Reset();
base.Reset();
}
}
}
+164
View File
@@ -0,0 +1,164 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator creates a moving average (middle band) with an upper band and lower band
/// fixed at k standard deviations above and below the moving average.
/// </summary>
public class BollingerBands : Indicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Gets the type of moving average
/// </summary>
public MovingAverageType MovingAverageType { get; }
/// <summary>
/// Gets the standard deviation
/// </summary>
public IndicatorBase<IndicatorDataPoint> StandardDeviation { get; }
/// <summary>
/// Gets the middle Bollinger band (moving average)
/// </summary>
public IndicatorBase<IndicatorDataPoint> MiddleBand { get; }
/// <summary>
/// Gets the upper Bollinger band (middleBand + k * stdDev)
/// </summary>
public IndicatorBase<IndicatorDataPoint> UpperBand { get; }
/// <summary>
/// Gets the lower Bollinger band (middleBand - k * stdDev)
/// </summary>
public IndicatorBase<IndicatorDataPoint> LowerBand { get; }
/// <summary>
/// Gets the Bollinger BandWidth indicator
/// BandWidth = ((Upper Band - Lower Band) / Middle Band) * 100
/// </summary>
public IndicatorBase<IndicatorDataPoint> BandWidth { get; }
/// <summary>
/// Gets the Bollinger %B
/// %B = (Price - Lower Band)/(Upper Band - Lower Band)
/// </summary>
public IndicatorBase<IndicatorDataPoint> PercentB { get; }
/// <summary>
/// Gets the Price level
/// </summary>
public IndicatorBase<IndicatorDataPoint> Price { get; }
/// <summary>
/// Initializes a new instance of the BollingerBands class
/// </summary>
/// <param name="period">The period of the standard deviation and moving average (middle band)</param>
/// <param name="k">The number of standard deviations specifying the distance between the middle band and upper or lower bands</param>
/// <param name="movingAverageType">The type of moving average to be used</param>
public BollingerBands(int period, decimal k, MovingAverageType movingAverageType = MovingAverageType.Simple)
: this($"BB({period},{k})", period, k, movingAverageType)
{
}
/// <summary>
/// Initializes a new instance of the BollingerBands class
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of the standard deviation and moving average (middle band)</param>
/// <param name="k">The number of standard deviations specifying the distance between the middle band and upper or lower bands</param>
/// <param name="movingAverageType">The type of moving average to be used</param>
public BollingerBands(string name, int period, decimal k, MovingAverageType movingAverageType = MovingAverageType.Simple)
: base(name)
{
WarmUpPeriod = period;
MovingAverageType = movingAverageType;
StandardDeviation = new StandardDeviation(name + "_StandardDeviation", period);
MiddleBand = movingAverageType.AsIndicator(name + "_MiddleBand", period);
LowerBand = MiddleBand.Minus(StandardDeviation.Times(k), name + "_LowerBand");
UpperBand = MiddleBand.Plus(StandardDeviation.Times(k), name + "_UpperBand");
var UpperMinusLower = UpperBand.Minus(LowerBand);
BandWidth = UpperMinusLower
.Over(MiddleBand)
.Times(new ConstantIndicator<IndicatorDataPoint>("ct", 100m), name + "_BandWidth");
Price = new Identity(name + "_Close");
PercentB = IndicatorExtensions.Over(
Price.Minus(LowerBand),
UpperMinusLower,
name + "_%B");
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => MiddleBand.IsReady && UpperBand.IsReady && LowerBand.IsReady && BandWidth.IsReady && PercentB.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Computes the next value of the following sub-indicators from the given state:
/// StandardDeviation, MiddleBand, UpperBand, LowerBand, BandWidth, %B
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>The input is returned unmodified.</returns>
protected override decimal ComputeNextValue(IndicatorDataPoint input)
{
StandardDeviation.Update(input);
MiddleBand.Update(input);
Price.Update(input);
return input.Value;
}
/// <summary>
/// Validate and Compute the next value for this indicator
/// </summary>
/// <param name="input">Input for this indicator</param>
/// <returns><see cref="IndicatorResult"/> of this update</returns>
/// <remarks>Override implemented to handle GH issue #4927</remarks>
protected override IndicatorResult ValidateAndComputeNextValue(IndicatorDataPoint input)
{
// Update our Indicators
var value = ComputeNextValue(input);
// If the STD = 0, we know that the our PercentB indicator will fail to update. This is
// because the denominator will be 0. When this is the case after fully ready we do not
// want the BollingerBands to emit an update because its PercentB property will be stale.
return IsReady && StandardDeviation.Current.Value == 0
? new IndicatorResult(value, IndicatorStatus.MathError)
: new IndicatorResult(value);
}
/// <summary>
/// Resets this indicator and all sub-indicators (StandardDeviation, LowerBand, MiddleBand, UpperBand, BandWidth, %B)
/// </summary>
public override void Reset()
{
StandardDeviation.Reset();
MiddleBand.Reset();
UpperBand.Reset();
LowerBand.Reset();
BandWidth.Reset();
PercentB.Reset();
base.Reset();
}
}
}
@@ -0,0 +1,184 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Abandoned Baby candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white (black) real body
/// - second candle: doji
/// - third candle: black(white) real body that moves well within the first candle's real body
/// - upside(downside) gap between the first candle and the doji(the shadows of the two candles don't touch)
/// - downside (upside) gap between the doji and the third candle(the shadows of the two candles don't touch)
/// The meaning of "doji" and "long" is specified with SetCandleSettings
/// The meaning of "moves well within" is specified with penetration and "moves" should mean the real body should
/// not be short ("short" is specified with SetCandleSettings) - Greg Morris wants it to be long, someone else want
/// it to be relatively long
/// The returned value is positive (+1) when it's an abandoned baby bottom or negative (-1) when it's
/// an abandoned baby top; the user should consider that an abandoned baby is significant when it appears in
/// an uptrend or downtrend, while this function does not consider the trend
/// </remarks>
public class AbandonedBaby : CandlestickPattern
{
private readonly decimal _penetration;
private readonly int _bodyDojiAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyDojiPeriodTotal;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="AbandonedBaby"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public AbandonedBaby(string name, decimal penetration = 0.3m)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod) + 2)
{
_penetration = penetration;
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="AbandonedBaby"/> class.
/// </summary>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public AbandonedBaby(decimal penetration)
: this("ABANDONEDBABY", penetration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AbandonedBaby"/> class.
/// </summary>
public AbandonedBaby()
: this("ABANDONEDBABY")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples > Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples > Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]);
}
if (Samples > Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, window[1]);
}
if (Samples > Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// 2nd: doji
GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, window[1]) &&
// 3rd: longer than short
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
((
// 1st white
GetCandleColor(window[2]) == CandleColor.White &&
// 3rd black
GetCandleColor(input) == CandleColor.Black &&
// 3rd closes well within 1st rb
input.Close < window[2].Close - GetRealBody(window[2]) * _penetration &&
// upside gap between 1st and 2nd
GetCandleGapUp(window[1], window[2]) &&
// downside gap between 2nd and 3rd
GetCandleGapDown(input, window[1])
)
||
(
// 1st black
GetCandleColor(window[2]) == CandleColor.Black &&
// 3rd white
GetCandleColor(input) == CandleColor.White &&
// 3rd closes well within 1st rb
input.Close > window[2].Close + GetRealBody(window[2]) * _penetration &&
// downside gap between 1st and 2nd
GetCandleGapDown(window[1], window[2]) &&
// upside gap between 2nd and 3rd
GetCandleGapUp(input, window[1])
)
)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod - 1]);
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, window[1]) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_bodyDojiPeriodTotal = 0;
_bodyShortPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,222 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Advance Block candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - three white candlesticks with consecutively higher closes
/// - each candle opens within or near the previous white real body
/// - first candle: long white with no or very short upper shadow(a short shadow is accepted too for more flexibility)
/// - second and third candles, or only third candle, show signs of weakening: progressively smaller white real bodies
/// and/or relatively long upper shadows; see below for specific conditions
/// The meanings of "long body", "short shadow", "far" and "near" are specified with SetCandleSettings;
/// The returned value is negative(-1): advance block is always bearish;
/// The user should consider that advance block is significant when it appears in uptrend, while this function
/// does not consider it
/// </remarks>
public class AdvanceBlock : CandlestickPattern
{
private readonly int _shadowShortAveragePeriod;
private readonly int _shadowLongAveragePeriod;
private readonly int _nearAveragePeriod;
private readonly int _farAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal[] _shadowShortPeriodTotal = new decimal[3];
private decimal[] _shadowLongPeriodTotal = new decimal[2];
private decimal[] _nearPeriodTotal = new decimal[3];
private decimal[] _farPeriodTotal = new decimal[3];
private decimal _bodyLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="AdvanceBlock"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public AdvanceBlock(string name)
: base(name, Math.Max(Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowShort).AveragePeriod),
Math.Max(CandleSettings.Get(CandleSettingType.Far).AveragePeriod, CandleSettings.Get(CandleSettingType.Near).AveragePeriod)),
CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 2 + 1)
{
_shadowShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowShort).AveragePeriod;
_shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
_farAveragePeriod = CandleSettings.Get(CandleSettingType.Far).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="AdvanceBlock"/> class.
/// </summary>
public AdvanceBlock()
: this("ADVANCEBLOCK")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowShortAveragePeriod)
{
_shadowShortPeriodTotal[2] += GetCandleRange(CandleSettingType.ShadowShort, window[2]);
_shadowShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowShort, window[1]);
_shadowShortPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowShort, input);
}
if (Samples >= Period - _shadowLongAveragePeriod)
{
_shadowLongPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowLong, window[1]);
_shadowLongPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowLong, input);
}
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]);
}
if (Samples >= Period - _nearAveragePeriod)
{
_nearPeriodTotal[2] += GetCandleRange(CandleSettingType.Near, window[2]);
_nearPeriodTotal[1] += GetCandleRange(CandleSettingType.Near, window[1]);
}
if (Samples >= Period - _farAveragePeriod)
{
_farPeriodTotal[2] += GetCandleRange(CandleSettingType.Far, window[2]);
_farPeriodTotal[1] += GetCandleRange(CandleSettingType.Far, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st white
GetCandleColor(window[2]) == CandleColor.White &&
// 2nd white
GetCandleColor(window[1]) == CandleColor.White &&
// 3rd white
GetCandleColor(input) == CandleColor.White &&
// consecutive higher closes
input.Close > window[1].Close && window[1].Close > window[2].Close &&
// 2nd opens within/near 1st real body
window[1].Open > window[2].Open &&
window[1].Open <= window[2].Close + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[2], window[2]) &&
// 3rd opens within/near 2nd real body
input.Open > window[1].Open &&
input.Open <= window[1].Close + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[1], window[1]) &&
// 1st: long real body
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// 1st: short upper shadow
GetUpperShadow(window[2]) < GetCandleAverage(CandleSettingType.ShadowShort, _shadowShortPeriodTotal[2], window[2]) &&
(
// ( 2 far smaller than 1 && 3 not longer than 2 )
// advance blocked with the 2nd, 3rd must not carry on the advance
(
GetRealBody(window[1]) < GetRealBody(window[2]) - GetCandleAverage(CandleSettingType.Far, _farPeriodTotal[2], window[2]) &&
GetRealBody(input) < GetRealBody(window[1]) + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[1], window[1])
) ||
// 3 far smaller than 2
// advance blocked with the 3rd
(
GetRealBody(input) < GetRealBody(window[1]) - GetCandleAverage(CandleSettingType.Far, _farPeriodTotal[1], window[1])
) ||
// ( 3 smaller than 2 && 2 smaller than 1 && (3 or 2 not short upper shadow) )
// advance blocked with progressively smaller real bodies and some upper shadows
(
GetRealBody(input) < GetRealBody(window[1]) &&
GetRealBody(window[1]) < GetRealBody(window[2]) &&
(
GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowShort, _shadowShortPeriodTotal[0], input) ||
GetUpperShadow(window[1]) > GetCandleAverage(CandleSettingType.ShadowShort, _shadowShortPeriodTotal[1], window[1])
)
) ||
// ( 3 smaller than 2 && 3 long upper shadow )
// advance blocked with 3rd candle's long upper shadow and smaller body
(
GetRealBody(input) < GetRealBody(window[1]) &&
GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal[0], input)
)
)
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 2; i >= 0; i--)
{
_shadowShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowShort, window[i]) -
GetCandleRange(CandleSettingType.ShadowShort, window[i + _shadowShortAveragePeriod]);
}
for (var i = 1; i >= 0; i--)
{
_shadowLongPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowLong, window[i]) -
GetCandleRange(CandleSettingType.ShadowLong, window[i + _shadowLongAveragePeriod]);
}
for (var i = 2; i >= 1; i--)
{
_farPeriodTotal[i] += GetCandleRange(CandleSettingType.Far, window[i]) -
GetCandleRange(CandleSettingType.Far, window[i + _farAveragePeriod]);
_nearPeriodTotal[i] += GetCandleRange(CandleSettingType.Near, window[i]) -
GetCandleRange(CandleSettingType.Near, window[i + _nearAveragePeriod]);
}
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[2 + _bodyLongAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowShortPeriodTotal = new decimal[3];
_shadowLongPeriodTotal = new decimal[2];
_nearPeriodTotal = new decimal[3];
_farPeriodTotal = new decimal[3];
_bodyLongPeriodTotal = 0;
base.Reset();
}
}
}
+131
View File
@@ -0,0 +1,131 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Belt-hold candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - long white(black) real body
/// - no or very short lower(upper) shadow
/// The meaning of "long" and "very short" is specified with SetCandleSettings
/// The returned value is positive(+1) when white(bullish), negative(-1) when black(bearish)
/// </remarks>
public class BeltHold : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="BeltHold"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public BeltHold(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod) + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="BeltHold"/> class.
/// </summary>
public BeltHold()
: this("BELTHOLD")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
return 0m;
}
decimal value;
if (
// long body
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, input) &&
(
(
// white body and very short lower shadow
GetCandleColor(input) == CandleColor.White &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
) ||
(
// black body and very short upper shadow
GetCandleColor(input) == CandleColor.Black &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
)
))
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
base.Reset();
}
}
}
+143
View File
@@ -0,0 +1,143 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Breakaway candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black(white)
/// - second candle: black(white) day whose body gaps down(up)
/// - third candle: black or white day with lower(higher) high and lower(higher) low than prior candle's
/// - fourth candle: black(white) day with lower(higher) high and lower(higher) low than prior candle's
/// - fifth candle: white(black) day that closes inside the gap, erasing the prior 3 days
/// The meaning of "long" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// The user should consider that breakaway is significant in a trend opposite to the last candle, while this
/// function does not consider it
/// </remarks>
public class Breakaway : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private decimal _bodyLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="Breakaway"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Breakaway(string name)
: base(name, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod + 4 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Breakaway"/> class.
/// </summary>
public Breakaway()
: this("BREAKAWAY")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[4]);
}
return 0m;
}
decimal value;
if (
// 1st long
GetRealBody(window[4]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[4]) &&
// 1st, 2nd, 4th same color, 5th opposite
GetCandleColor(window[4]) == GetCandleColor(window[3]) &&
GetCandleColor(window[3]) == GetCandleColor(window[1]) &&
(int)GetCandleColor(window[1]) == -(int)GetCandleColor(input) &&
(
(
// when 1st is black:
GetCandleColor(window[4]) == CandleColor.Black &&
// 2nd gaps down
GetRealBodyGapDown(window[3], window[4]) &&
// 3rd has lower high and low than 2nd
window[2].High < window[3].High && window[2].Low < window[3].Low &&
// 4th has lower high and low than 3rd
window[1].High < window[2].High && window[1].Low < window[2].Low &&
// 5th closes inside the gap
input.Close > window[3].Open && input.Close < window[4].Close
)
||
(
// when 1st is white:
GetCandleColor(window[4]) == CandleColor.White &&
// 2nd gaps up
GetRealBodyGapUp(window[3], window[4]) &&
// 3rd has higher high and low than 2nd
window[2].High > window[3].High && window[2].Low > window[3].Low &&
// 4th has higher high and low than 3rd
window[1].High > window[2].High && window[1].Low > window[2].Low &&
// 5th closes inside the gap
input.Close < window[3].Open && input.Close > window[4].Close
)
)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[4]) -
GetCandleRange(CandleSettingType.BodyLong, window[4 + _bodyLongAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,118 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Types of candlestick settings
/// </summary>
public enum CandleSettingType
{
/// <summary>
/// Real body is long when it's longer than the average of the 10 previous candles' real body (0)
/// </summary>
BodyLong,
/// <summary>
/// Real body is very long when it's longer than 3 times the average of the 10 previous candles' real body (1)
/// </summary>
BodyVeryLong,
/// <summary>
/// Real body is short when it's shorter than the average of the 10 previous candles' real bodies (2)
/// </summary>
BodyShort,
/// <summary>
/// Real body is like doji's body when it's shorter than 10% the average of the 10 previous candles' high-low range (3)
/// </summary>
BodyDoji,
/// <summary>
/// Shadow is long when it's longer than the real body (4)
/// </summary>
ShadowLong,
/// <summary>
/// Shadow is very long when it's longer than 2 times the real body (5)
/// </summary>
ShadowVeryLong,
/// <summary>
/// Shadow is short when it's shorter than half the average of the 10 previous candles' sum of shadows (6)
/// </summary>
ShadowShort,
/// <summary>
/// Shadow is very short when it's shorter than 10% the average of the 10 previous candles' high-low range (7)
/// </summary>
ShadowVeryShort,
/// <summary>
/// When measuring distance between parts of candles or width of gaps
/// "near" means "&lt;= 20% of the average of the 5 previous candles' high-low range" (8)
/// </summary>
Near,
/// <summary>
/// When measuring distance between parts of candles or width of gaps
/// "far" means "&gt;= 60% of the average of the 5 previous candles' high-low range" (9)
/// </summary>
Far,
/// <summary>
/// When measuring distance between parts of candles or width of gaps
/// "equal" means "&lt;= 5% of the average of the 5 previous candles' high-low range" (10)
/// </summary>
Equal
}
/// <summary>
/// Types of candlestick ranges
/// </summary>
public enum CandleRangeType
{
/// <summary>
/// The part of the candle between open and close (0)
/// </summary>
RealBody,
/// <summary>
/// The complete range of the candle (1)
/// </summary>
HighLow,
/// <summary>
/// The shadows (or tails) of the candle (2)
/// </summary>
Shadows
}
/// <summary>
/// Colors of a candle
/// </summary>
public enum CandleColor
{
/// <summary>
/// White is an up candle (close higher or equal than open) (1)
/// </summary>
White = 1,
/// <summary>
/// Black is a down candle (close lower than open) (-1)
/// </summary>
Black = -1
}
}
@@ -0,0 +1,110 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections.Generic;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Candle settings for all candlestick patterns
/// </summary>
public static class CandleSettings
{
/// <summary>
/// Default settings for all candle setting types
/// </summary>
private static readonly Dictionary<CandleSettingType, CandleSetting> DefaultSettings = new Dictionary<CandleSettingType, CandleSetting>
{
{ CandleSettingType.BodyLong, new CandleSetting(CandleRangeType.RealBody, 10, 1m) },
{ CandleSettingType.BodyVeryLong, new CandleSetting(CandleRangeType.RealBody, 10, 3m) },
{ CandleSettingType.BodyShort, new CandleSetting(CandleRangeType.RealBody, 10, 1m) },
{ CandleSettingType.BodyDoji, new CandleSetting(CandleRangeType.HighLow, 10, 0.1m) },
{ CandleSettingType.ShadowLong, new CandleSetting(CandleRangeType.RealBody, 0, 1m) },
{ CandleSettingType.ShadowVeryLong, new CandleSetting(CandleRangeType.RealBody, 0, 2m) },
{ CandleSettingType.ShadowShort, new CandleSetting(CandleRangeType.Shadows, 10, 1m) },
{ CandleSettingType.ShadowVeryShort, new CandleSetting(CandleRangeType.HighLow, 10, 0.1m) },
{ CandleSettingType.Near, new CandleSetting(CandleRangeType.HighLow, 5, 0.2m) },
{ CandleSettingType.Far, new CandleSetting(CandleRangeType.HighLow, 5, 0.6m) },
{ CandleSettingType.Equal, new CandleSetting(CandleRangeType.HighLow, 5, 0.05m) }
};
/// <summary>
/// Returns the candle setting for the requested type
/// </summary>
/// <param name="type">The candle setting type</param>
public static CandleSetting Get(CandleSettingType type)
{
CandleSetting setting;
DefaultSettings.TryGetValue(type, out setting);
return setting;
}
/// <summary>
/// Changes the default candle setting for the requested type
/// </summary>
/// <param name="type">The candle setting type</param>
/// <param name="setting">The candle setting</param>
public static void Set(CandleSettingType type, CandleSetting setting)
{
DefaultSettings[type] = setting;
}
}
/// <summary>
/// Represents a candle setting
/// </summary>
public class CandleSetting
{
/// <summary>
/// The candle range type
/// </summary>
public CandleRangeType RangeType
{
get;
private set;
}
/// <summary>
/// The number of previous candles to average
/// </summary>
public int AveragePeriod
{
get;
private set;
}
/// <summary>
/// A multiplier to calculate candle ranges
/// </summary>
public decimal Factor
{
get;
private set;
}
/// <summary>
/// Creates an instance of the <see cref="CandleSetting"/> class
/// </summary>
/// <param name="rangeType">The range type</param>
/// <param name="averagePeriod">The average period</param>
/// <param name="factor">The factor</param>
public CandleSetting(CandleRangeType rangeType, int averagePeriod, decimal factor)
{
RangeType = rangeType;
AveragePeriod = averagePeriod;
Factor = factor;
}
}
}
@@ -0,0 +1,151 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Abstract base class for a candlestick pattern indicator
/// </summary>
public abstract class CandlestickPattern : WindowIndicator<IBaseDataBar>
{
/// <summary>
/// Creates a new <see cref="CandlestickPattern"/> with the specified name
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The number of data points to hold in the window</param>
protected CandlestickPattern(string name, int period)
: base(name, period)
{
}
/// <summary>
/// Returns the candle color of a candle
/// </summary>
/// <param name="tradeBar">The input candle</param>
protected static CandleColor GetCandleColor(IBaseDataBar tradeBar)
{
return tradeBar.Close >= tradeBar.Open ? CandleColor.White : CandleColor.Black;
}
/// <summary>
/// Returns the distance between the close and the open of a candle
/// </summary>
/// <param name="tradeBar">The input candle</param>
protected static decimal GetRealBody(IBaseDataBar tradeBar)
{
return Math.Abs(tradeBar.Close - tradeBar.Open);
}
/// <summary>
/// Returns the full range of the candle
/// </summary>
/// <param name="tradeBar">The input candle</param>
protected static decimal GetHighLowRange(IBaseDataBar tradeBar)
{
return tradeBar.High - tradeBar.Low;
}
/// <summary>
/// Returns the range of a candle
/// </summary>
/// <param name="type">The type of setting to use</param>
/// <param name="tradeBar">The input candle</param>
protected static decimal GetCandleRange(CandleSettingType type, IBaseDataBar tradeBar)
{
switch (CandleSettings.Get(type).RangeType)
{
case CandleRangeType.RealBody:
return GetRealBody(tradeBar);
case CandleRangeType.HighLow:
return GetHighLowRange(tradeBar);
case CandleRangeType.Shadows:
return GetUpperShadow(tradeBar) + GetLowerShadow(tradeBar);
default:
return 0m;
}
}
/// <summary>
/// Returns true if the candle is higher than the previous one
/// </summary>
protected static bool GetCandleGapUp(IBaseDataBar tradeBar, IBaseDataBar previousBar)
{
return tradeBar.Low > previousBar.High;
}
/// <summary>
/// Returns true if the candle is lower than the previous one
/// </summary>
protected static bool GetCandleGapDown(IBaseDataBar tradeBar, IBaseDataBar previousBar)
{
return tradeBar.High < previousBar.Low;
}
/// <summary>
/// Returns true if the candle is higher than the previous one (with no body overlap)
/// </summary>
protected static bool GetRealBodyGapUp(IBaseDataBar tradeBar, IBaseDataBar previousBar)
{
return Math.Min(tradeBar.Open, tradeBar.Close) > Math.Max(previousBar.Open, previousBar.Close);
}
/// <summary>
/// Returns true if the candle is lower than the previous one (with no body overlap)
/// </summary>
protected static bool GetRealBodyGapDown(IBaseDataBar tradeBar, IBaseDataBar previousBar)
{
return Math.Max(tradeBar.Open, tradeBar.Close) < Math.Min(previousBar.Open, previousBar.Close);
}
/// <summary>
/// Returns the range of the candle's lower shadow
/// </summary>
/// <param name="tradeBar">The input candle</param>
protected static decimal GetLowerShadow(IBaseDataBar tradeBar)
{
return (tradeBar.Close >= tradeBar.Open ? tradeBar.Open : tradeBar.Close) - tradeBar.Low;
}
/// <summary>
/// Returns the range of the candle's upper shadow
/// </summary>
/// <param name="tradeBar">The input candle</param>
protected static decimal GetUpperShadow(IBaseDataBar tradeBar)
{
return tradeBar.High - (tradeBar.Close >= tradeBar.Open ? tradeBar.Close : tradeBar.Open);
}
/// <summary>
/// Returns the average range of the previous candles
/// </summary>
/// <param name="type">The type of setting to use</param>
/// <param name="sum">The sum of the previous candles ranges</param>
/// <param name="tradeBar">The input candle</param>
protected static decimal GetCandleAverage(CandleSettingType type, decimal sum, IBaseDataBar tradeBar)
{
var defaultSetting = CandleSettings.Get(type);
return defaultSetting.Factor *
(defaultSetting.AveragePeriod != 0 ? sum / defaultSetting.AveragePeriod : GetCandleRange(type, tradeBar)) /
(defaultSetting.RangeType == CandleRangeType.Shadows ? 2.0m : 1.0m);
}
}
}
@@ -0,0 +1,131 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Closing Marubozu candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - long white(black) real body
/// - no or very short upper(lower) shadow
/// The meaning of "long" and "very short" is specified with SetCandleSettings
/// The returned value is positive(+1) when white(bullish), negative(-1) when black(bearish)
/// </remarks>
public class ClosingMarubozu : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="ClosingMarubozu"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ClosingMarubozu(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod) + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ClosingMarubozu"/> class.
/// </summary>
public ClosingMarubozu()
: this("CLOSINGMARUBOZU")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
return 0m;
}
decimal value;
if (
// long body
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, input) &&
(
(
// white body and very short upper shadow
GetCandleColor(input) == CandleColor.White &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
) ||
(
// black body and very short lower shadow
GetCandleColor(input) == CandleColor.Black &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
)
))
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,137 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Concealed Baby Swallow candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: black marubozu (very short shadows)
/// - second candle: black marubozu(very short shadows)
/// - third candle: black candle that opens gapping down but has an upper shadow that extends into the prior body
/// - fourth candle: black candle that completely engulfs the third candle, including the shadows
/// The meanings of "very short shadow" are specified with SetCandleSettings;
/// The returned value is positive(+1): concealing baby swallow is always bullish;
/// The user should consider that concealing baby swallow is significant when it appears in downtrend, while
/// this function does not consider it
/// </remarks>
public class ConcealedBabySwallow : CandlestickPattern
{
private readonly int _shadowVeryShortAveragePeriod;
private decimal[] _shadowVeryShortPeriodTotal = new decimal[4];
/// <summary>
/// Initializes a new instance of the <see cref="ConcealedBabySwallow"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ConcealedBabySwallow(string name)
: base(name, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod + 3 + 1)
{
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ConcealedBabySwallow"/> class.
/// </summary>
public ConcealedBabySwallow()
: this("CONCEALEDBABYSWALLOW")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal[3] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[3]);
_shadowVeryShortPeriodTotal[2] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[2]);
_shadowVeryShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st black
GetCandleColor(window[3]) == CandleColor.Black &&
// 2nd black
GetCandleColor(window[2]) == CandleColor.Black &&
// 3rd black
GetCandleColor(window[1]) == CandleColor.Black &&
// 4th black
GetCandleColor(input) == CandleColor.Black &&
// 1st: marubozu
GetLowerShadow(window[3]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[3], window[3]) &&
GetUpperShadow(window[3]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[3], window[3]) &&
// 2nd: marubozu
GetLowerShadow(window[2]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[2], window[2]) &&
GetUpperShadow(window[2]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[2], window[2]) &&
// 3rd: opens gapping down
GetRealBodyGapDown(window[1], window[2]) &&
// and has an upper shadow
GetUpperShadow(window[1]) > GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
// that extends into the prior body
window[1].High > window[2].Close &&
// 4th: engulfs the 3rd including the shadows
input.High > window[1].High && input.Low < window[1].Low
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 3; i >= 1; i--)
{
_shadowVeryShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[i]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[i + _shadowVeryShortAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowVeryShortPeriodTotal = new decimal[4];
base.Reset();
}
}
}
@@ -0,0 +1,133 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Counterattack candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black (white)
/// - second candle: long white(black) with close equal to the prior close
/// The meaning of "equal" and "long" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// The user should consider that counterattack is significant in a trend, while this function does not consider it
/// </remarks>
public class Counterattack : CandlestickPattern
{
private readonly int _equalAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal _equalPeriodTotal;
private decimal[] _bodyLongPeriodTotal = new decimal[2];
/// <summary>
/// Initializes a new instance of the <see cref="Counterattack"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Counterattack(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.Equal).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 1 + 1)
{
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Counterattack"/> class.
/// </summary>
public Counterattack()
: this("COUNTERATTACK")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]);
}
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal[1] += GetCandleRange(CandleSettingType.BodyLong, window[1]);
_bodyLongPeriodTotal[0] += GetCandleRange(CandleSettingType.BodyLong, input);
}
return 0m;
}
decimal value;
if (
// opposite candles
(int)GetCandleColor(window[1]) == -(int)GetCandleColor(input) &&
// 1st long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[1], window[1]) &&
// 2nd long
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[0], input) &&
// equal closes
input.Close <= window[1].Close + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1]) &&
input.Close >= window[1].Close - GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1])
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, input) -
GetCandleRange(CandleSettingType.Equal, window[_equalAveragePeriod + 1]);
for (var i = 1; i >= 0; i--)
{
_bodyLongPeriodTotal[i] += GetCandleRange(CandleSettingType.BodyLong, window[i]) -
GetCandleRange(CandleSettingType.BodyLong, window[i + _bodyLongAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_equalPeriodTotal = 0;
_bodyLongPeriodTotal = new decimal[2];
base.Reset();
}
}
}
@@ -0,0 +1,135 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Dark Cloud Cover candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white candle
/// - second candle: black candle that opens above previous day high and closes within previous day real body;
/// Greg Morris wants the close to be below the midpoint of the previous real body
/// The meaning of "long" is specified with SetCandleSettings, the penetration of the first real body is specified
/// with optInPenetration
/// The returned value is negative(-1): dark cloud cover is always bearish
/// The user should consider that a dark cloud cover is significant when it appears in an uptrend, while
/// this function does not consider it
/// </remarks>
public class DarkCloudCover : CandlestickPattern
{
private readonly decimal _penetration;
private readonly int _bodyLongAveragePeriod;
private decimal _bodyLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="DarkCloudCover"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public DarkCloudCover(string name, decimal penetration = 0.5m)
: base(name, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod + 1 + 1)
{
_penetration = penetration;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="DarkCloudCover"/> class.
/// </summary>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public DarkCloudCover(decimal penetration)
: this("DARKCLOUDCOVER", penetration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DarkCloudCover"/> class.
/// </summary>
public DarkCloudCover()
: this("DARKCLOUDCOVER")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st: white
GetCandleColor(window[1]) == CandleColor.White &&
// long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) &&
// 2nd: black
GetCandleColor(input) == CandleColor.Black &&
// open above prior high
input.Open > window[1].High &&
// close within prior body
input.Close > window[1].Open &&
input.Close < window[1].Close - GetRealBody(window[1]) * _penetration
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
base.Reset();
}
}
}
+100
View File
@@ -0,0 +1,100 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Doji candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - open quite equal to close
/// How much can be the maximum distance between open and close is specified with SetCandleSettings
/// The returned value is always positive(+1) but this does not mean it is bullish: doji shows uncertainty and it is
/// neither bullish nor bearish when considered alone
/// </remarks>
public class Doji : CandlestickPattern
{
private readonly int _bodyDojiAveragePeriod;
private decimal _bodyDojiPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="Doji"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Doji(string name)
: base(name, CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod + 1)
{
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Doji"/> class.
/// </summary>
public Doji()
: this("DOJI")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
return 0m;
}
var value = GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) ? 1m : 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyDojiPeriodTotal = 0m;
base.Reset();
}
}
}
+131
View File
@@ -0,0 +1,131 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Doji Star candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long real body
/// - second candle: star(open gapping up in an uptrend or down in a downtrend) with a doji
/// The meaning of "doji" and "long" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// it's defined bullish when the long candle is white and the star gaps up, bearish when the long candle
/// is black and the star gaps down; the user should consider that a doji star is bullish when it appears
/// in an uptrend and it's bearish when it appears in a downtrend, so to determine the bullishness or
/// bearishness of the pattern the trend must be analyzed
/// </remarks>
public class DojiStar : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyDojiAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyDojiPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="DojiStar"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public DojiStar(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod) + 1 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="DojiStar"/> class.
/// </summary>
public DojiStar()
: this("DOJISTAR")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 1 && Samples < Period - 1)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
return 0m;
}
decimal value;
if (
// 1st: long real body
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) &&
// 2nd: doji
GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) &&
// that gaps up if 1st is white
((GetCandleColor(window[1]) == CandleColor.White && GetRealBodyGapUp(input, window[1]))
||
// or down if 1st is black
(GetCandleColor(window[1]) == CandleColor.Black && GetRealBodyGapDown(input, window[1]))
))
value = -(int)GetCandleColor(window[1]);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]);
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
_bodyDojiPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,122 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Dragonfly Doji candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - doji body
/// - open and close at the high of the day = no or very short upper shadow
/// - lower shadow(to distinguish from other dojis, here lower shadow should not be very short)
/// The meaning of "doji" and "very short" is specified with SetCandleSettings
/// The returned value is always positive(+1) but this does not mean it is bullish: dragonfly doji must be considered
/// relatively to the trend
/// </remarks>
public class DragonflyDoji : CandlestickPattern
{
private readonly int _bodyDojiAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private decimal _bodyDojiPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="DragonflyDoji"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public DragonflyDoji(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod) + 1)
{
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="DragonflyDoji"/> class.
/// </summary>
public DragonflyDoji()
: this("DRAGONFLYDOJI")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) &&
GetLowerShadow(input) > GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyDojiPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,91 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Engulfing candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first: black (white) real body
/// - second: white(black) real body that engulfs the prior real body
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// The user should consider that an engulfing must appear in a downtrend if bullish or in an uptrend if bearish,
/// while this function does not consider it
/// </remarks>
public class Engulfing : CandlestickPattern
{
/// <summary>
/// Initializes a new instance of the <see cref="Engulfing"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Engulfing(string name)
: base(name, 3)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Engulfing"/> class.
/// </summary>
public Engulfing()
: this("ENGULFING")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
return 0m;
}
decimal value;
if (
// white engulfs black
(GetCandleColor(input) == CandleColor.White && GetCandleColor(window[1]) == CandleColor.Black &&
input.Close > window[1].Open && input.Open < window[1].Close
)
||
// black engulfs white
(GetCandleColor(input) == CandleColor.Black && GetCandleColor(window[1]) == CandleColor.White &&
input.Open > window[1].Close && input.Close < window[1].Open
)
)
value = (int)GetCandleColor(input);
else
value = 0;
return value;
}
}
}
@@ -0,0 +1,166 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Evening Doji Star candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white real body
/// - second candle: doji gapping up
/// - third candle: black real body that moves well within the first candle's real body
/// The meaning of "doji" and "long" is specified with SetCandleSettings
/// The meaning of "moves well within" is specified with penetration and "moves" should mean the real body should
/// not be short ("short" is specified with SetCandleSettings) - Greg Morris wants it to be long, someone else want
/// it to be relatively long
/// The returned value is negative(-1): evening star is always bearish;
/// The user should consider that an evening star is significant when it appears in an uptrend,
/// while this function does not consider the trend
/// </remarks>
public class EveningDojiStar : CandlestickPattern
{
private readonly decimal _penetration;
private readonly int _bodyDojiAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyDojiPeriodTotal;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="EveningDojiStar"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public EveningDojiStar(string name, decimal penetration = 0.3m)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod) + 2 + 1)
{
_penetration = penetration;
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="EveningDojiStar"/> class.
/// </summary>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public EveningDojiStar(decimal penetration)
: this("EVENINGDOJISTAR", penetration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EveningDojiStar"/> class.
/// </summary>
public EveningDojiStar()
: this("EVENINGDOJISTAR")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 2 && Samples < Period - 2)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyDojiAveragePeriod - 1 && Samples < Period - 1)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// white
GetCandleColor(window[2]) == CandleColor.White &&
// 2nd: doji
GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, window[1]) &&
// gapping up
GetRealBodyGapUp(window[1], window[2]) &&
// 3rd: longer than short
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// black real body
GetCandleColor(input) == CandleColor.Black &&
// closing well within 1st rb
input.Close < window[2].Close - GetRealBody(window[2]) * _penetration
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 2]);
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, window[1]) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod + 1]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_bodyDojiPeriodTotal = 0;
_bodyShortPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,159 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Evening Star candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white real body
/// - second candle: star(short real body gapping up)
/// - third candle: black real body that moves well within the first candle's real body
/// The meaning of "short" and "long" is specified with SetCandleSettings
/// The meaning of "moves well within" is specified with penetration and "moves" should mean the real body should
/// not be short ("short" is specified with SetCandleSettings) - Greg Morris wants it to be long, someone else want
/// it to be relatively long
/// The returned value is negative(-1): evening star is always bearish;
/// The user should consider that an evening star is significant when it appears in an uptrend,
/// while this function does not consider the trend
/// </remarks>
public class EveningStar : CandlestickPattern
{
private readonly decimal _penetration;
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
private decimal _bodyShortPeriodTotal2;
/// <summary>
/// Initializes a new instance of the <see cref="EveningStar"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public EveningStar(string name, decimal penetration = 0.3m)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 2 + 1)
{
_penetration = penetration;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="EveningStar"/> class.
/// </summary>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public EveningStar(decimal penetration)
: this("EVENINGSTAR", penetration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="EveningStar"/> class.
/// </summary>
public EveningStar()
: this("EVENINGSTAR")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 2 && Samples < Period - 2)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyShortAveragePeriod && Samples < Period)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, window[1]);
_bodyShortPeriodTotal2 += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// white
GetCandleColor(window[2]) == CandleColor.White &&
// 2nd: short
GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, window[1]) &&
// gapping up
GetRealBodyGapUp(window[1], window[2]) &&
// 3rd: longer than short
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal2, input) &&
// black real body
GetCandleColor(input) == CandleColor.Black &&
// closing well within 1st rb
input.Close < window[2].Close - GetRealBody(window[2]) * _penetration
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 2]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, window[1]) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod + 1]);
_bodyShortPeriodTotal2 += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_bodyShortPeriodTotal = 0;
_bodyShortPeriodTotal2 = 0;
base.Reset();
}
}
}
@@ -0,0 +1,138 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Up/Down-gap side-by-side white lines candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - upside or downside gap (between the bodies)
/// - first candle after the window: white candlestick
/// - second candle after the window: white candlestick with similar size(near the same) and about the same
/// open(equal) of the previous candle
/// - the second candle does not close the window
/// The meaning of "near" and "equal" is specified with SetCandleSettings
/// The returned value is positive(+1) or negative(-1): the user should consider that upside
/// or downside gap side-by-side white lines is significant when it appears in a trend, while this function
/// does not consider the trend
/// </remarks>
public class GapSideBySideWhite : CandlestickPattern
{
private readonly int _nearAveragePeriod;
private readonly int _equalAveragePeriod;
private decimal _nearPeriodTotal;
private decimal _equalPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="GapSideBySideWhite"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public GapSideBySideWhite(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.Near).AveragePeriod, CandleSettings.Get(CandleSettingType.Equal).AveragePeriod) + 2 + 1)
{
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="GapSideBySideWhite"/> class.
/// </summary>
public GapSideBySideWhite()
: this("GAPSIDEBYSIDEWHITE")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _nearAveragePeriod)
{
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[1]);
}
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]);
}
return 0m;
}
decimal value;
if (
( // upside or downside gap between the 1st candle and both the next 2 candles
(GetRealBodyGapUp(window[1], window[2]) && GetRealBodyGapUp(input, window[2]))
||
(GetRealBodyGapDown(window[1], window[2]) && GetRealBodyGapDown(input, window[2]))
) &&
// 2nd: white
GetCandleColor(window[1]) == CandleColor.White &&
// 3rd: white
GetCandleColor(input) == CandleColor.White &&
// same size 2 and 3
GetRealBody(input) >= GetRealBody(window[1]) - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[1]) &&
GetRealBody(input) <= GetRealBody(window[1]) + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[1]) &&
// same open 2 and 3
input.Open >= window[1].Open - GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1]) &&
input.Open <= window[1].Open + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1])
)
value = GetRealBodyGapUp(window[1], window[2]) ? 1m : -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[1]) -
GetCandleRange(CandleSettingType.Near, window[1 + _nearAveragePeriod]);
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]) -
GetCandleRange(CandleSettingType.Equal, window[1 + _equalAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_nearPeriodTotal = 0;
_equalPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,122 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Gravestone Doji candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - doji body
/// - open and close at the low of the day = no or very short lower shadow
/// - upper shadow(to distinguish from other dojis, here upper shadow should not be very short)
/// The meaning of "doji" and "very short" is specified with SetCandleSettings
/// The returned value is always positive(+1) but this does not mean it is bullish: gravestone doji must be considered
/// relatively to the trend
/// </remarks>
public class GravestoneDoji : CandlestickPattern
{
private readonly int _bodyDojiAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private decimal _bodyDojiPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="GravestoneDoji"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public GravestoneDoji(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod) + 1)
{
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="GravestoneDoji"/> class.
/// </summary>
public GravestoneDoji()
: this("GRAVESTONEDOJI")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) &&
GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyDojiPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
base.Reset();
}
}
}
+154
View File
@@ -0,0 +1,154 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Hammer candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - small real body
/// - long lower shadow
/// - no, or very short, upper shadow
/// - body below or near the lows of the previous candle
/// The meaning of "short", "long" and "near the lows" is specified with SetCandleSettings;
/// The returned value is positive(+1): hammer is always bullish;
/// The user should consider that a hammer must appear in a downtrend, while this function does not consider it
/// </remarks>
public class Hammer : CandlestickPattern
{
private readonly int _bodyShortAveragePeriod;
private readonly int _shadowLongAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _nearAveragePeriod;
private decimal _bodyShortPeriodTotal;
private decimal _shadowLongPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
private decimal _nearPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="Hammer"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Hammer(string name)
: base(name, Math.Max(Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod), CandleSettings.Get(CandleSettingType.Near).AveragePeriod) + 1 + 1)
{
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Hammer"/> class.
/// </summary>
public Hammer()
: this("HAMMER")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
if (Samples >= Period - _shadowLongAveragePeriod)
{
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _nearAveragePeriod - 1 && Samples < Period - 1)
{
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, input);
}
return 0m;
}
decimal value;
if (
// small rb
GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// long lower shadow
GetLowerShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input) &&
// very short upper shadow
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) &&
// rb near the prior candle's lows
Math.Min(input.Close, input.Open) <= window[1].Low + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[1])
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input) -
GetCandleRange(CandleSettingType.ShadowLong, window[_shadowLongAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[1]) -
GetCandleRange(CandleSettingType.Near, window[_nearAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyShortPeriodTotal = 0m;
_shadowLongPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
_nearPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,154 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Hanging Man candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - small real body
/// - long lower shadow
/// - no, or very short, upper shadow
/// - body above or near the highs of the previous candle
/// The meaning of "short", "long" and "near the highs" is specified with SetCandleSettings;
/// The returned value is negative (-1): hanging man is always bearish;
/// The user should consider that a hanging man must appear in an uptrend, while this function does not consider it
/// </remarks>
public class HangingMan : CandlestickPattern
{
private readonly int _bodyShortAveragePeriod;
private readonly int _shadowLongAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _nearAveragePeriod;
private decimal _bodyShortPeriodTotal;
private decimal _shadowLongPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
private decimal _nearPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="HangingMan"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public HangingMan(string name)
: base(name, Math.Max(Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod), CandleSettings.Get(CandleSettingType.Near).AveragePeriod) + 1 + 1)
{
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="HangingMan"/> class.
/// </summary>
public HangingMan()
: this("HANGINGMAN")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
if (Samples >= Period - _shadowLongAveragePeriod)
{
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _nearAveragePeriod - 1 && Samples < Period - 1)
{
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, input);
}
return 0m;
}
decimal value;
if (
// small rb
GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// long lower shadow
GetLowerShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input) &&
// very short upper shadow
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) &&
// rb near the prior candle's highs
Math.Min(input.Close, input.Open) >= window[1].High - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[1])
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input) -
GetCandleRange(CandleSettingType.ShadowLong, window[_shadowLongAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[1]) -
GetCandleRange(CandleSettingType.Near, window[_nearAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyShortPeriodTotal = 0m;
_shadowLongPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
_nearPeriodTotal = 0m;
base.Reset();
}
}
}
+127
View File
@@ -0,0 +1,127 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Harami candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white (black) real body
/// - second candle: short real body totally engulfed by the first
/// The meaning of "short" and "long" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// The user should consider that a harami is significant when it appears in a downtrend if bullish or
/// in an uptrend when bearish, while this function does not consider the trend
/// </remarks>
public class Harami : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="Harami"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Harami(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod) + 1 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Harami"/> class.
/// </summary>
public Harami()
: this("HARAMI")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 1 && Samples < Period - 1)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) &&
// 2nd: short
GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// engulfed by 1st
Math.Max(input.Close, input.Open) < Math.Max(window[1].Close, window[1].Open) &&
Math.Min(input.Close, input.Open) > Math.Min(window[1].Close, window[1].Open)
)
value = -(int)GetCandleColor(window[1]);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
_bodyShortPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,127 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Harami Cross candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white (black) real body
/// - second candle: doji totally engulfed by the first
/// The meaning of "doji" and "long" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// The user should consider that a harami cross is significant when it appears in a downtrend if bullish or
/// in an uptrend when bearish, while this function does not consider the trend
/// </remarks>
public class HaramiCross : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyDojiAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyDojiPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="HaramiCross"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public HaramiCross(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod) + 1 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="HaramiCross"/> class.
/// </summary>
public HaramiCross()
: this("HARAMICROSS")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 1 && Samples < Period - 1)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) &&
// 2nd: doji
GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) &&
// engulfed by 1st
Math.Max(input.Close, input.Open) < Math.Max(window[1].Close, window[1].Open) &&
Math.Min(input.Close, input.Open) > Math.Min(window[1].Close, window[1].Open)
)
value = -(int)GetCandleColor(window[1]);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]);
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
_bodyDojiPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,121 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// High-Wave Candle candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - short real body
/// - very long upper and lower shadow
/// The meaning of "short" and "very long" is specified with SetCandleSettings
/// The returned value is positive(+1) when white or negative(-1) when black;
/// it does not mean bullish or bearish
/// </remarks>
public class HighWaveCandle : CandlestickPattern
{
private readonly int _bodyShortAveragePeriod;
private readonly int _shadowVeryLongAveragePeriod;
private decimal _bodyShortPeriodTotal;
private decimal _shadowVeryLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="HighWaveCandle"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public HighWaveCandle(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowVeryLong).AveragePeriod) + 1)
{
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
_shadowVeryLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="HighWaveCandle"/> class.
/// </summary>
public HighWaveCandle()
: this("HIGHWAVECANDLE")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
if (Samples >= Period - _shadowVeryLongAveragePeriod)
{
_shadowVeryLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryLong, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowVeryLong, _shadowVeryLongPeriodTotal, input) &&
GetLowerShadow(input) > GetCandleAverage(CandleSettingType.ShadowVeryLong, _shadowVeryLongPeriodTotal, input)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
_shadowVeryLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryLong, input) -
GetCandleRange(CandleSettingType.ShadowVeryLong, window[_shadowVeryLongAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyShortPeriodTotal = 0m;
_shadowVeryLongPeriodTotal = 0m;
base.Reset();
}
}
}
+154
View File
@@ -0,0 +1,154 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Hikkake candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first and second candle: inside bar (2nd has lower high and higher low than 1st)
/// - third candle: lower high and lower low than 2nd(higher high and higher low than 2nd)
/// The returned value for the hikkake bar is positive(+1) or negative(-1) meaning bullish or bearish hikkake
/// Confirmation could come in the next 3 days with:
/// - a day that closes higher than the high(lower than the low) of the 2nd candle
/// The returned value for the confirmation bar is equal to 1 + the bullish hikkake result or -1 - the bearish hikkake result
/// Note: if confirmation and a new hikkake come at the same bar, only the new hikkake is reported(the new hikkake
/// overwrites the confirmation of the old hikkake)
/// </remarks>
public class Hikkake : CandlestickPattern
{
private int _patternIndex;
private int _patternResult;
/// <summary>
/// Initializes a new instance of the <see cref="Hikkake"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Hikkake(string name)
: base(name, 5 + 1)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Hikkake"/> class.
/// </summary>
public Hikkake()
: this("HIKKAKE")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= 3)
{
// copy here the pattern recognition code below
// 1st + 2nd: lower high and higher low
if (window[1].High < window[2].High && window[1].Low > window[2].Low &&
// (bull) 3rd: lower high and lower low
((input.High < window[1].High && input.Low < window[1].Low)
||
// (bear) 3rd: higher high and higher low
(input.High > window[1].High && input.Low > window[1].Low)
)
)
{
_patternResult = (input.High < window[1].High ? 1 : -1);
_patternIndex = (int)Samples - 1;
}
else
// search for confirmation if hikkake was no more than 3 bars ago
if (Samples <= _patternIndex + 4 &&
// close higher than the high of 2nd
((_patternResult > 0 && input.Close > window[(int)Samples - _patternIndex].High)
||
// close lower than the low of 2nd
(_patternResult < 0 && input.Close < window[(int)Samples - _patternIndex].Low)
)
)
_patternIndex = 0;
}
return 0m;
}
decimal value;
// 1st + 2nd: lower high and higher low
if (window[1].High < window[2].High && window[1].Low > window[2].Low &&
// (bull) 3rd: lower high and lower low
((input.High < window[1].High && input.Low < window[1].Low)
||
// (bear) 3rd: higher high and higher low
(input.High > window[1].High && input.Low > window[1].Low)
)
)
{
_patternResult = (input.High < window[1].High ? 1 : -1);
_patternIndex = (int) Samples - 1;
value = _patternResult;
}
else
{
// search for confirmation if hikkake was no more than 3 bars ago
if (Samples <= _patternIndex + 4 &&
// close higher than the high of 2nd
((_patternResult > 0 && input.Close > window[(int) Samples - _patternIndex].High)
||
// close lower than the low of 2nd
(_patternResult < 0 && input.Close < window[(int) Samples - _patternIndex].Low)
)
)
{
value = _patternResult + (_patternResult > 0 ? 1 : -1);
_patternIndex = 0;
}
else
value = 0;
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_patternIndex = 0;
_patternResult = 0;
base.Reset();
}
}
}
@@ -0,0 +1,198 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Hikkake Modified candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle
/// - second candle: candle with range less than first candle and close near the bottom(near the top)
/// - third candle: lower high and higher low than 2nd
/// - fourth candle: lower high and lower low(higher high and higher low) than 3rd
/// The returned value for the hikkake bar is positive(+1) or negative(-1) meaning bullish or bearish hikkake
/// Confirmation could come in the next 3 days with:
/// - a day that closes higher than the high(lower than the low) of the 3rd candle
/// The returned value for the confirmation bar is equal to 1 + the bullish hikkake result or -1 - the bearish hikkake result
/// Note: if confirmation and a new hikkake come at the same bar, only the new hikkake is reported(the new hikkake
/// overwrites the confirmation of the old hikkake);
/// The user should consider that modified hikkake is a reversal pattern, while hikkake could be both a reversal
/// or a continuation pattern, so bullish(bearish) modified hikkake is significant when appearing in a downtrend(uptrend)
/// </remarks>
public class HikkakeModified : CandlestickPattern
{
private readonly int _nearAveragePeriod;
private decimal _nearPeriodTotal;
private int _patternIndex;
private int _patternResult;
/// <summary>
/// Initializes a new instance of the <see cref="HikkakeModified"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public HikkakeModified(string name)
: base(name, Math.Max(1, CandleSettings.Get(CandleSettingType.Near).AveragePeriod) + 5 + 1)
{
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="HikkakeModified"/> class.
/// </summary>
public HikkakeModified()
: this("HIKKAKEMODIFIED")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _nearAveragePeriod - 3 && Samples < Period - 3)
{
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[2]);
}
else if (Samples >= Period - 3)
{
// copy here the pattern recognition code below
// 2nd: lower high and higher low than 1st
if (window[2].High < window[3].High && window[2].Low > window[3].Low &&
// 3rd: lower high and higher low than 2nd
window[1].High < window[2].High && window[1].Low > window[2].Low &&
// (bull) 4th: lower high and lower low
((input.High < window[1].High && input.Low < window[1].Low &&
// (bull) 2nd: close near the low
window[2].Close <= window[2].Low + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[2])
)
||
// (bear) 4th: higher high and higher low
(input.High > window[1].High && input.Low > window[1].Low &&
// (bull) 2nd: close near the top
window[2].Close >= window[2].High - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[2])
)
)
)
{
_patternResult = (input.High < window[1].High ? 1 : -1);
_patternIndex = (int) Samples - 1;
}
else
{
// search for confirmation if modified hikkake was no more than 3 bars ago
if (Samples <= _patternIndex + 4 &&
// close higher than the high of 3rd
((_patternResult > 0 && input.Close > window[(int) Samples - _patternIndex].High)
||
// close lower than the low of 3rd
(_patternResult < 0 && input.Close < window[(int) Samples - _patternIndex].Low))
)
_patternIndex = 0;
}
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[2]) -
GetCandleRange(CandleSettingType.Near, window[(int)Samples - 1]);
}
return 0m;
}
decimal value;
// 2nd: lower high and higher low than 1st
if (window[2].High < window[3].High && window[2].Low > window[3].Low &&
// 3rd: lower high and higher low than 2nd
window[1].High < window[2].High && window[1].Low > window[2].Low &&
// (bull) 4th: lower high and lower low
((input.High < window[1].High && input.Low < window[1].Low &&
// (bull) 2nd: close near the low
window[2].Close <= window[2].Low + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[2])
)
||
// (bear) 4th: higher high and higher low
(input.High > window[1].High && input.Low > window[1].Low &&
// (bull) 2nd: close near the top
window[2].Close >= window[2].High - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[2])
)
)
)
{
_patternResult = (input.High < window[1].High ? 1 : -1);
_patternIndex = (int) Samples - 1;
value = _patternResult;
}
else
{
// search for confirmation if modified hikkake was no more than 3 bars ago
if (Samples <= _patternIndex + 4 &&
// close higher than the high of 3rd
((_patternResult > 0 && input.Close > window[(int)Samples - _patternIndex].High)
||
// close lower than the low of 3rd
(_patternResult < 0 && input.Close < window[(int)Samples - _patternIndex].Low))
)
{
value = _patternResult + (_patternResult > 0 ? 1 : -1);
_patternIndex = 0;
}
else
value = 0;
}
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[2]) -
GetCandleRange(CandleSettingType.Near, window[_nearAveragePeriod + 5]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_nearPeriodTotal = 0;
_patternIndex = 0;
_patternResult = 0;
base.Reset();
}
}
}
@@ -0,0 +1,131 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Homing Pigeon candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black candle
/// - second candle: short black real body completely inside the previous day's body
/// The meaning of "short" and "long" is specified with SetCandleSettings
/// The returned value is positive(+1): homing pigeon is always bullish;
/// The user should consider that homing pigeon is significant when it appears in a downtrend,
/// while this function does not consider the trend
/// </remarks>
public class HomingPigeon : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="HomingPigeon"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public HomingPigeon(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod) + 1 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="HomingPigeon"/> class.
/// </summary>
public HomingPigeon()
: this("HOMINGPIGEON")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]);
}
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st black
GetCandleColor(window[1]) == CandleColor.Black &&
// 2nd black
GetCandleColor(input) == CandleColor.Black &&
// 1st long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) &&
// 2nd short
GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// 2nd engulfed by 1st
input.Open < window[1].Open &&
input.Close > window[1].Close
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
_bodyShortPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,153 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Identical Three Crows candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - three consecutive and declining black candlesticks
/// - each candle must have no or very short lower shadow
/// - each candle after the first must open at or very close to the prior candle's close
/// The meaning of "very short" is specified with SetCandleSettings;
/// the meaning of "very close" is specified with SetCandleSettings(Equal);
/// The returned value is negative(-1): identical three crows is always bearish;
/// The user should consider that identical 3 crows is significant when it appears after a mature advance or at high levels,
/// while this function does not consider it
/// </remarks>
public class IdenticalThreeCrows : CandlestickPattern
{
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _equalAveragePeriod;
private decimal[] _shadowVeryShortPeriodTotal = new decimal[3];
private decimal[] _equalPeriodTotal = new decimal[3];
/// <summary>
/// Initializes a new instance of the <see cref="IdenticalThreeCrows"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public IdenticalThreeCrows(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod, CandleSettings.Get(CandleSettingType.Equal).AveragePeriod) + 2 + 1)
{
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="IdenticalThreeCrows"/> class.
/// </summary>
public IdenticalThreeCrows()
: this("IDENTICALTHREECROWS")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal[2] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[2]);
_shadowVeryShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
_shadowVeryShortPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal[2] += GetCandleRange(CandleSettingType.Near, window[2]);
_equalPeriodTotal[1] += GetCandleRange(CandleSettingType.Near, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st black
GetCandleColor(window[2]) == CandleColor.Black &&
// very short lower shadow
GetLowerShadow(window[2]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[2], window[2]) &&
// 2nd black
GetCandleColor(window[1]) == CandleColor.Black &&
// very short lower shadow
GetLowerShadow(window[1]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
// 3rd black
GetCandleColor(input) == CandleColor.Black &&
// very short lower shadow
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
// three declining
window[2].Close > window[1].Close &&
window[1].Close > input.Close &&
// 2nd black opens very close to 1st close
window[1].Open <= window[2].Close + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal[2], window[2]) &&
window[1].Open >= window[2].Close - GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal[2], window[2]) &&
// 3rd black opens very close to 2nd close
input.Open <= window[1].Close + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal[1], window[1]) &&
input.Open >= window[1].Close - GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal[1], window[1])
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 2; i >= 0; i--)
{
_shadowVeryShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[i]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[i + _shadowVeryShortAveragePeriod]);
}
for (var i = 2; i >= 1; i--)
{
_equalPeriodTotal[i] += GetCandleRange(CandleSettingType.Equal, window[i]) -
GetCandleRange(CandleSettingType.Equal, window[i + _equalAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowVeryShortPeriodTotal = new decimal[3];
_equalPeriodTotal = new decimal[3];
base.Reset();
}
}
}
+131
View File
@@ -0,0 +1,131 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// In-Neck candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black candle
/// - second candle: white candle with open below previous day low and close slightly into previous day body
/// The meaning of "equal" is specified with SetCandleSettings
/// The returned value is negative(-1): in-neck is always bearish
/// The user should consider that in-neck is significant when it appears in a downtrend, while this function
/// does not consider it
/// </remarks>
public class InNeck : CandlestickPattern
{
private readonly int _equalAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal _equalPeriodTotal;
private decimal _bodyLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="InNeck"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public InNeck(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.Equal).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 1 + 1)
{
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="InNeck"/> class.
/// </summary>
public InNeck()
: this("INNECK")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]);
}
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st: black
GetCandleColor(window[1]) == CandleColor.Black &&
// long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) &&
// 2nd: white
GetCandleColor(input) == CandleColor.White &&
// open below prior low
input.Open < window[1].Low &&
// close slightly into prior body
input.Close <= window[1].Close + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1]) &&
input.Close >= window[1].Close
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]) -
GetCandleRange(CandleSettingType.Equal, window[_equalAveragePeriod + 1]);
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_equalPeriodTotal = 0m;
_bodyLongPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,142 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Inverted Hammer candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - small real body
/// - long upper shadow
/// - no, or very short, lower shadow
/// - gap down
/// The meaning of "short", "very short" and "long" is specified with SetCandleSettings;
/// The returned value is positive(+1): inverted hammer is always bullish;
/// The user should consider that an inverted hammer must appear in a downtrend, while this function does not consider it
/// </remarks>
public class InvertedHammer : CandlestickPattern
{
private readonly int _bodyShortAveragePeriod;
private readonly int _shadowLongAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private decimal _bodyShortPeriodTotal;
private decimal _shadowLongPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="InvertedHammer"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public InvertedHammer(string name)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod) + 1 + 1)
{
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="InvertedHammer"/> class.
/// </summary>
public InvertedHammer()
: this("INVERTEDHAMMER")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
if (Samples >= Period - _shadowLongAveragePeriod)
{
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
return 0m;
}
decimal value;
if (
// small rb
GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// long upper shadow
GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input) &&
// very short lower shadow
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) &&
// gap down
GetRealBodyGapDown(input, window[1])
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input) -
GetCandleRange(CandleSettingType.ShadowLong, window[_shadowLongAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyShortPeriodTotal = 0m;
_shadowLongPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
base.Reset();
}
}
}
+141
View File
@@ -0,0 +1,141 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Kicking candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: marubozu
/// - second candle: opposite color marubozu
/// - gap between the two candles: upside gap if black then white, downside gap if white then black
/// The meaning of "long body" and "very short shadow" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish
/// </remarks>
public class Kicking : CandlestickPattern
{
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal[] _shadowVeryShortPeriodTotal = new decimal[2];
private decimal[] _bodyLongPeriodTotal = new decimal[2];
/// <summary>
/// Initializes a new instance of the <see cref="Kicking"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Kicking(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 1 + 1)
{
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Kicking"/> class.
/// </summary>
public Kicking()
: this("KICKING")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
_shadowVeryShortPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal[1] += GetCandleRange(CandleSettingType.BodyLong, window[1]);
_bodyLongPeriodTotal[0] += GetCandleRange(CandleSettingType.BodyLong, input);
}
return 0m;
}
decimal value;
if (
// opposite candles
(int)GetCandleColor(window[1]) == -(int)GetCandleColor(input) &&
// 1st marubozu
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[1], window[1]) &&
GetUpperShadow(window[1]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
GetLowerShadow(window[1]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
// 2nd marubozu
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[0], input) &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
// gap
(
(GetCandleColor(window[1]) == CandleColor.Black && GetCandleGapUp(input, window[1]))
||
(GetCandleColor(window[1]) == CandleColor.White && GetCandleGapDown(input, window[1]))
)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 1; i >= 0; i--)
{
_shadowVeryShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[i]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[i + _shadowVeryShortAveragePeriod]);
_bodyLongPeriodTotal[i] += GetCandleRange(CandleSettingType.BodyLong, window[i]) -
GetCandleRange(CandleSettingType.BodyLong, window[i + _bodyLongAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowVeryShortPeriodTotal = new decimal[2];
_bodyLongPeriodTotal = new decimal[2];
base.Reset();
}
}
}
@@ -0,0 +1,142 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Kicking (bull/bear determined by the longer marubozu) candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: marubozu
/// - second candle: opposite color marubozu
/// - gap between the two candles: upside gap if black then white, downside gap if white then black
/// The meaning of "long body" and "very short shadow" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish; the longer of the two
/// marubozu determines the bullishness or bearishness of this pattern
/// </remarks>
public class KickingByLength : CandlestickPattern
{
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal[] _shadowVeryShortPeriodTotal = new decimal[2];
private decimal[] _bodyLongPeriodTotal = new decimal[2];
/// <summary>
/// Initializes a new instance of the <see cref="KickingByLength"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public KickingByLength(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 1 + 1)
{
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="KickingByLength"/> class.
/// </summary>
public KickingByLength()
: this("KICKINGBYLENGTH")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
_shadowVeryShortPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal[1] += GetCandleRange(CandleSettingType.BodyLong, window[1]);
_bodyLongPeriodTotal[0] += GetCandleRange(CandleSettingType.BodyLong, input);
}
return 0m;
}
decimal value;
if (
// opposite candles
(int)GetCandleColor(window[1]) == -(int)GetCandleColor(input) &&
// 1st marubozu
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[1], window[1]) &&
GetUpperShadow(window[1]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
GetLowerShadow(window[1]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
// 2nd marubozu
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[0], input) &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
// gap
(
(GetCandleColor(window[1]) == CandleColor.Black && GetCandleGapUp(input, window[1]))
||
(GetCandleColor(window[1]) == CandleColor.White && GetCandleGapDown(input, window[1]))
)
)
value = (int)GetCandleColor(GetRealBody(input) > GetRealBody(window[1]) ? input : window[1]);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 1; i >= 0; i--)
{
_shadowVeryShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[i]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[i + _shadowVeryShortAveragePeriod]);
_bodyLongPeriodTotal[i] += GetCandleRange(CandleSettingType.BodyLong, window[i]) -
GetCandleRange(CandleSettingType.BodyLong, window[i + _bodyLongAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowVeryShortPeriodTotal = new decimal[2];
_bodyLongPeriodTotal = new decimal[2];
base.Reset();
}
}
}
@@ -0,0 +1,125 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Ladder Bottom candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - three black candlesticks with consecutively lower opens and closes
/// - fourth candle: black candle with an upper shadow(it's supposed to be not very short)
/// - fifth candle: white candle that opens above prior candle's body and closes above prior candle's high
/// The meaning of "very short" is specified with SetCandleSettings
/// The returned value is positive (+1): ladder bottom is always bullish;
/// The user should consider that ladder bottom is significant when it appears in a downtrend,
/// while this function does not consider it
/// </remarks>
public class LadderBottom : CandlestickPattern
{
private readonly int _shadowVeryShortAveragePeriod;
private decimal _shadowVeryShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="LadderBottom"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public LadderBottom(string name)
: base(name, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod + 4 + 1)
{
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="LadderBottom"/> class.
/// </summary>
public LadderBottom()
: this("LADDERBOTTOM")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
}
return 0m;
}
decimal value;
if (
// 3 black candlesticks
GetCandleColor(window[4]) == CandleColor.Black &&
GetCandleColor(window[3]) == CandleColor.Black &&
GetCandleColor(window[2]) == CandleColor.Black &&
// with consecutively lower opens
window[4].Open > window[3].Open && window[3].Open > window[2].Open &&
// and closes
window[4].Close > window[3].Close && window[3].Close > window[2].Close &&
// 4th: black with an upper shadow
GetCandleColor(window[1]) == CandleColor.Black &&
GetUpperShadow(window[1]) > GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, window[1]) &&
// 5th: white
GetCandleColor(input) == CandleColor.White &&
// that opens above prior candle's body
input.Open > window[1].Open &&
// and closes above prior candle's high
input.Close > window[1].High
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowVeryShortPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,122 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Long Legged Doji candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - doji body
/// - one or two long shadows
/// The meaning of "doji" is specified with SetCandleSettings
/// The returned value is always positive(+1) but this does not mean it is bullish: long legged doji shows uncertainty
/// </remarks>
public class LongLeggedDoji : CandlestickPattern
{
private readonly int _bodyDojiAveragePeriod;
private readonly int _shadowLongAveragePeriod;
private decimal _bodyDojiPeriodTotal;
private decimal _shadowLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="LongLeggedDoji"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public LongLeggedDoji(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod) + 1)
{
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
_shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="LongLeggedDoji"/> class.
/// </summary>
public LongLeggedDoji()
: this("LONGLEGGEDDOJI")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
if (Samples >= Period - _shadowLongAveragePeriod)
{
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) &&
(GetLowerShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input)
||
GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input)
)
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input) -
GetCandleRange(CandleSettingType.ShadowLong, window[_shadowLongAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyDojiPeriodTotal = 0m;
_shadowLongPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,120 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Long Line Candle candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - long real body
/// - short upper and lower shadow
/// The meaning of "long" and "short" is specified with SetCandleSettings
/// The returned value is positive(+1) when white(bullish), negative(-1) when black(bearish)
/// </remarks>
public class LongLineCandle : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _shadowShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _shadowShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="LongLineCandle"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public LongLineCandle(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowShort).AveragePeriod) + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_shadowShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="LongLineCandle"/> class.
/// </summary>
public LongLineCandle()
: this("LONGLINECANDLE")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _shadowShortAveragePeriod)
{
_shadowShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowShort, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, input) &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowShort, _shadowShortPeriodTotal, input) &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowShort, _shadowShortPeriodTotal, input)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod]);
_shadowShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowShort, input) -
GetCandleRange(CandleSettingType.ShadowShort, window[_shadowShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
_shadowShortPeriodTotal = 0m;
base.Reset();
}
}
}
+120
View File
@@ -0,0 +1,120 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Marubozu candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - long real body
/// - no or very short upper and lower shadow
/// The meaning of "long" and "very short" is specified with SetCandleSettings
/// The returned value is positive(+1) when white(bullish), negative(-1) when black(bearish)
/// </remarks>
public class Marubozu : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="Marubozu"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Marubozu(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod) + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Marubozu"/> class.
/// </summary>
public Marubozu()
: this("MARUBOZU")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, input) &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
base.Reset();
}
}
}
+168
View File
@@ -0,0 +1,168 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Mat Hold candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white candle
/// - upside gap between the first and the second bodies
/// - second candle: small black candle
/// - third and fourth candles: falling small real body candlesticks(commonly black) that hold within the long
/// white candle's body and are higher than the reaction days of the rising three methods
/// - fifth candle: white candle that opens above the previous small candle's close and closes higher than the
/// high of the highest reaction day
/// The meaning of "short" and "long" is specified with SetCandleSettings;
/// "hold within" means "a part of the real body must be within";
/// penetration is the maximum percentage of the first white body the reaction days can penetrate(it is
/// to specify how much the reaction days should be "higher than the reaction days of the rising three methods")
/// The returned value is positive(+1): mat hold is always bullish
/// </remarks>
public class MatHold : CandlestickPattern
{
private readonly decimal _penetration;
private readonly int _bodyShortAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal[] _bodyPeriodTotal = new decimal[5];
/// <summary>
/// Initializes a new instance of the <see cref="MatHold"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public MatHold(string name, decimal penetration = 0.5m)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 4 + 1)
{
_penetration = penetration;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="MatHold"/> class.
/// </summary>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public MatHold(decimal penetration)
: this("MATHOLD", penetration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MatHold"/> class.
/// </summary>
public MatHold()
: this("MATHOLD")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples > Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples > Period - _bodyShortAveragePeriod)
{
_bodyPeriodTotal[3] += GetCandleRange(CandleSettingType.BodyShort, window[3]);
_bodyPeriodTotal[2] += GetCandleRange(CandleSettingType.BodyShort, window[2]);
_bodyPeriodTotal[1] += GetCandleRange(CandleSettingType.BodyShort, window[1]);
}
if (Samples > Period - _bodyLongAveragePeriod)
{
_bodyPeriodTotal[4] += GetCandleRange(CandleSettingType.BodyLong, window[4]);
}
return 0m;
}
decimal value;
if (
// 1st long, then 3 small
GetRealBody(window[4]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyPeriodTotal[4], window[4]) &&
GetRealBody(window[3]) < GetCandleAverage(CandleSettingType.BodyShort, _bodyPeriodTotal[3], window[3]) &&
GetRealBody(window[2]) < GetCandleAverage(CandleSettingType.BodyShort, _bodyPeriodTotal[2], window[2]) &&
GetRealBody(window[1]) < GetCandleAverage(CandleSettingType.BodyShort, _bodyPeriodTotal[1], window[1]) &&
// white, black, 2 black or white, white
GetCandleColor(window[4]) == CandleColor.White &&
GetCandleColor(window[3]) == CandleColor.Black &&
GetCandleColor(input) == CandleColor.White &&
// upside gap 1st to 2nd
GetRealBodyGapUp(window[3], window[4]) &&
// 3rd to 4th hold within 1st: a part of the real body must be within 1st real body
Math.Min(window[2].Open, window[2].Close) < window[4].Close &&
Math.Min(window[1].Open, window[1].Close) < window[4].Close &&
// reaction days penetrate first body less than optInPenetration percent
Math.Min(window[2].Open, window[2].Close) > window[4].Close - GetRealBody(window[4]) * _penetration &&
Math.Min(window[1].Open, window[1].Close) > window[4].Close - GetRealBody(window[4]) * _penetration &&
// 2nd to 4th are falling
Math.Max(window[2].Close, window[2].Open) < window[3].Open &&
Math.Max(window[1].Close, window[1].Open) < Math.Max(window[2].Close, window[2].Open) &&
// 5th opens above the prior close
input.Open > window[1].Close &&
// 5th closes above the highest high of the reaction days
input.Close > Math.Max(Math.Max(window[3].High, window[2].High), window[1].High)
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyPeriodTotal[4] += GetCandleRange(CandleSettingType.BodyLong, window[4]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 4]);
for (var i = 3; i >= 1; i--)
{
_bodyPeriodTotal[i] += GetCandleRange(CandleSettingType.BodyShort, window[i]) -
GetCandleRange(CandleSettingType.BodyShort, window[i + _bodyShortAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyPeriodTotal = new decimal[5];
base.Reset();
}
}
}
@@ -0,0 +1,112 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Matching Low candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: black candle
/// - second candle: black candle with the close equal to the previous close
/// The meaning of "equal" is specified with SetCandleSettings
/// The returned value is always positive(+1): matching low is always bullish;
/// </remarks>
public class MatchingLow : CandlestickPattern
{
private readonly int _equalAveragePeriod;
private decimal _equalPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="MatchingLow"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public MatchingLow(string name)
: base(name, CandleSettings.Get(CandleSettingType.Equal).AveragePeriod + 1 + 1)
{
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="MatchingLow"/> class.
/// </summary>
public MatchingLow()
: this("MATCHINGLOW")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]);
}
return 0m;
}
decimal value;
if (
// first black
GetCandleColor(window[1]) == CandleColor.Black &&
// second black
GetCandleColor(input) == CandleColor.Black &&
// 1st and 2nd same close
input.Close <= window[1].Close + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1]) &&
input.Close >= window[1].Close - GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1])
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]) -
GetCandleRange(CandleSettingType.Equal, window[_equalAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_equalPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,166 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Morning Doji Star candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black real body
/// - second candle: doji gapping down
/// - third candle: white real body that moves well within the first candle's real body
/// The meaning of "doji" and "long" is specified with SetCandleSettings
/// The meaning of "moves well within" is specified with penetration and "moves" should mean the real body should
/// not be short ("short" is specified with SetCandleSettings) - Greg Morris wants it to be long, someone else want
/// it to be relatively long
/// The returned value is positive(+1): morning doji star is always bullish;
/// the user should consider that a morning star is significant when it appears in a downtrend,
/// while this function does not consider the trend
/// </remarks>
public class MorningDojiStar : CandlestickPattern
{
private readonly decimal _penetration;
private readonly int _bodyDojiAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyDojiPeriodTotal;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="MorningDojiStar"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public MorningDojiStar(string name, decimal penetration = 0.3m)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod) + 2 + 1)
{
_penetration = penetration;
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="MorningDojiStar"/> class.
/// </summary>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public MorningDojiStar(decimal penetration)
: this("MORNINGDOJISTAR", penetration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MorningDojiStar"/> class.
/// </summary>
public MorningDojiStar()
: this("MORNINGDOJISTAR")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 2 && Samples < Period - 2)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyDojiAveragePeriod - 1 && Samples < Period - 1)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// black
GetCandleColor(window[2]) == CandleColor.Black &&
// 2nd: doji
GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, window[1]) &&
// gapping down
GetRealBodyGapDown(window[1], window[2]) &&
// 3rd: longer than short
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// white real body
GetCandleColor(input) == CandleColor.White &&
// closing well within 1st rb
input.Close > window[2].Close + GetRealBody(window[2]) * _penetration
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 2]);
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, window[1]) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod + 1]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_bodyDojiPeriodTotal = 0;
_bodyShortPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,159 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Morning Star candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black real body
/// - second candle: star(Short real body gapping down)
/// - third candle: white real body that moves well within the first candle's real body
/// The meaning of "short" and "long" is specified with SetCandleSettings
/// The meaning of "moves well within" is specified with penetration and "moves" should mean the real body should
/// not be short ("short" is specified with SetCandleSettings) - Greg Morris wants it to be long, someone else want
/// it to be relatively long
/// The returned value is positive(+1): morning star is always bullish;
/// The user should consider that a morning star is significant when it appears in a downtrend,
/// while this function does not consider the trend
/// </remarks>
public class MorningStar : CandlestickPattern
{
private readonly decimal _penetration;
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
private decimal _bodyShortPeriodTotal2;
/// <summary>
/// Initializes a new instance of the <see cref="MorningStar"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public MorningStar(string name, decimal penetration = 0.3m)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 2 + 1)
{
_penetration = penetration;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="MorningStar"/> class.
/// </summary>
/// <param name="penetration">Percentage of penetration of a candle within another candle</param>
public MorningStar(decimal penetration)
: this("MORNINGSTAR", penetration)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="MorningStar"/> class.
/// </summary>
public MorningStar()
: this("MORNINGSTAR")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 2 && Samples < Period - 2)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyShortAveragePeriod - 1 && Samples < Period - 1)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
_bodyShortPeriodTotal2 += GetCandleRange(CandleSettingType.BodyShort, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// black
GetCandleColor(window[2]) == CandleColor.Black &&
// 2nd: short
GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, window[1]) &&
// gapping down
GetRealBodyGapDown(window[1], window[2]) &&
// 3rd: longer than short
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal2, input) &&
// white real body
GetCandleColor(input) == CandleColor.White &&
// closing well within 1st rb
input.Close > window[2].Close + GetRealBody(window[2]) * _penetration
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 2]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, window[1]) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod + 1]);
_bodyShortPeriodTotal2 += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_bodyShortPeriodTotal = 0;
_bodyShortPeriodTotal2 = 0;
base.Reset();
}
}
}
+131
View File
@@ -0,0 +1,131 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// On-Neck candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black candle
/// - second candle: white candle with open below previous day low and close equal to previous day low
/// The meaning of "equal" is specified with SetCandleSettings
/// The returned value is negative(-1): on-neck is always bearish
/// The user should consider that on-neck is significant when it appears in a downtrend, while this function
/// does not consider it
/// </remarks>
public class OnNeck : CandlestickPattern
{
private readonly int _equalAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal _equalPeriodTotal;
private decimal _bodyLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="OnNeck"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public OnNeck(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.Equal).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 1 + 1)
{
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="OnNeck"/> class.
/// </summary>
public OnNeck()
: this("ONNECK")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]);
}
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st: black
GetCandleColor(window[1]) == CandleColor.Black &&
// long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) &&
// 2nd: white
GetCandleColor(input) == CandleColor.White &&
// open below prior low
input.Open < window[1].Low &&
// close equal to prior low
input.Close <= window[1].Low + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1]) &&
input.Close >= window[1].Low - GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1])
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]) -
GetCandleRange(CandleSettingType.Equal, window[_equalAveragePeriod + 1]);
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_equalPeriodTotal = 0m;
_bodyLongPeriodTotal = 0m;
base.Reset();
}
}
}
+126
View File
@@ -0,0 +1,126 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Piercing candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black candle
/// - second candle: long white candle with open below previous day low and close at least at 50% of previous day
/// real body
/// The meaning of "long" is specified with SetCandleSettings
/// The returned value is positive(+1): piercing pattern is always bullish
/// The user should consider that a piercing pattern is significant when it appears in a downtrend, while
/// this function does not consider it
/// </remarks>
public class Piercing : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private decimal[] _bodyLongPeriodTotal = new decimal[2];
/// <summary>
/// Initializes a new instance of the <see cref="Piercing"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Piercing(string name)
: base(name, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod + 1 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Piercing"/> class.
/// </summary>
public Piercing()
: this("PIERCING")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal[1] += GetCandleRange(CandleSettingType.BodyLong, window[1]);
_bodyLongPeriodTotal[0] += GetCandleRange(CandleSettingType.BodyLong, input);
}
return 0m;
}
decimal value;
if (
// 1st: black
GetCandleColor(window[1]) == CandleColor.Black &&
// long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[1], window[1]) &&
// 2nd: white
GetCandleColor(input) == CandleColor.White &&
// long
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[0], input) &&
// open below prior low
input.Open < window[1].Low &&
// close within prior body
input.Close < window[1].Open &&
// above midpoint
input.Close > window[1].Close + GetRealBody(window[1]) * 0.5m
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 1; i >= 0; i--)
{
_bodyLongPeriodTotal[i] += GetCandleRange(CandleSettingType.BodyLong, window[i]) -
GetCandleRange(CandleSettingType.BodyLong, window[i + _bodyLongAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = new decimal[2];
base.Reset();
}
}
}
@@ -0,0 +1,147 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Rickshaw Man candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - doji body
/// - two long shadows
/// - body near the midpoint of the high-low range
/// The meaning of "doji" and "near" is specified with SetCandleSettings
/// The returned value is always positive(+1) but this does not mean it is bullish: rickshaw man shows uncertainty
/// </remarks>
public class RickshawMan : CandlestickPattern
{
private readonly int _bodyDojiAveragePeriod;
private readonly int _shadowLongAveragePeriod;
private readonly int _nearAveragePeriod;
private decimal _bodyDojiPeriodTotal;
private decimal _shadowLongPeriodTotal;
private decimal _nearPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="RickshawMan"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public RickshawMan(string name)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.Near).AveragePeriod) + 1)
{
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
_shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="RickshawMan"/> class.
/// </summary>
public RickshawMan()
: this("RICKSHAWMAN")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
if (Samples >= Period - _shadowLongAveragePeriod)
{
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input);
}
if (Samples >= Period - _nearAveragePeriod)
{
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, input);
}
return 0m;
}
decimal value;
if (
// doji
GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) &&
// long shadow
GetLowerShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input) &&
// long shadow
GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input) &&
// body near midpoint
(
Math.Min(input.Open, input.Close)
<= input.Low + GetHighLowRange(input) / 2 + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, input)
&&
Math.Max(input.Open, input.Close)
>= input.Low + GetHighLowRange(input) / 2 - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, input)
)
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input) -
GetCandleRange(CandleSettingType.ShadowLong, window[_shadowLongAveragePeriod]);
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, input) -
GetCandleRange(CandleSettingType.Near, window[_nearAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyDojiPeriodTotal = 0;
_shadowLongPeriodTotal = 0;
_nearPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,152 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Rising/Falling Three Methods candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white (black) candlestick
/// - then: group of falling(rising) small real body candlesticks(commonly black (white)) that hold within
/// the prior long candle's range: ideally they should be three but two or more than three are ok too
/// - final candle: long white(black) candle that opens above(below) the previous small candle's close
/// and closes above(below) the first long candle's close
/// The meaning of "short" and "long" is specified with SetCandleSettings; here only patterns with 3 small candles
/// are considered;
/// The returned value is positive(+1) or negative(-1)
/// </remarks>
public class RiseFallThreeMethods : CandlestickPattern
{
private readonly int _bodyShortAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal[] _bodyPeriodTotal = new decimal[5];
/// <summary>
/// Initializes a new instance of the <see cref="RiseFallThreeMethods"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public RiseFallThreeMethods(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 4 + 1)
{
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="RiseFallThreeMethods"/> class.
/// </summary>
public RiseFallThreeMethods()
: this("RISEFALLTHREEMETHODS")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples > Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples > Period - _bodyShortAveragePeriod)
{
_bodyPeriodTotal[3] += GetCandleRange(CandleSettingType.BodyShort, window[3]);
_bodyPeriodTotal[2] += GetCandleRange(CandleSettingType.BodyShort, window[2]);
_bodyPeriodTotal[1] += GetCandleRange(CandleSettingType.BodyShort, window[1]);
}
if (Samples > Period - _bodyLongAveragePeriod)
{
_bodyPeriodTotal[4] += GetCandleRange(CandleSettingType.BodyLong, window[4]);
_bodyPeriodTotal[0] += GetCandleRange(CandleSettingType.BodyLong, input);
}
return 0m;
}
decimal value;
if (
// 1st long, then 3 small, 5th long
GetRealBody(window[4]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyPeriodTotal[4], window[4]) &&
GetRealBody(window[3]) < GetCandleAverage(CandleSettingType.BodyShort, _bodyPeriodTotal[3], window[3]) &&
GetRealBody(window[2]) < GetCandleAverage(CandleSettingType.BodyShort, _bodyPeriodTotal[2], window[2]) &&
GetRealBody(window[1]) < GetCandleAverage(CandleSettingType.BodyShort, _bodyPeriodTotal[1], window[1]) &&
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyPeriodTotal[0], input) &&
// white, 3 black, white || black, 3 white, black
(int)GetCandleColor(window[4]) == -(int)GetCandleColor(window[3]) &&
GetCandleColor(window[3]) == GetCandleColor(window[2]) &&
GetCandleColor(window[2]) == GetCandleColor(window[1]) &&
(int)GetCandleColor(window[1]) == -(int)GetCandleColor(input) &&
// 2nd to 4th hold within 1st: a part of the real body must be within 1st range
Math.Min(window[3].Open, window[3].Close) < window[4].High && Math.Max(window[3].Open, window[3].Close) > window[4].Low &&
Math.Min(window[2].Open, window[2].Close) < window[4].High && Math.Max(window[2].Open, window[2].Close) > window[4].Low &&
Math.Min(window[1].Open, window[1].Close) < window[4].High && Math.Max(window[1].Open, window[1].Close) > window[4].Low &&
// 2nd to 4th are falling (rising)
window[2].Close * (int)GetCandleColor(window[4]) < window[3].Close * (int)GetCandleColor(window[4]) &&
window[1].Close * (int)GetCandleColor(window[4]) < window[2].Close * (int)GetCandleColor(window[4]) &&
// 5th opens above (below) the prior close
input.Open * (int)GetCandleColor(window[4]) > window[1].Close * (int)GetCandleColor(window[4]) &&
// 5th closes above (below) the 1st close
input.Close * (int)GetCandleColor(window[4]) > window[4].Close * (int)GetCandleColor(window[4])
)
value = (int)GetCandleColor(window[4]);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyPeriodTotal[4] += GetCandleRange(CandleSettingType.BodyLong, window[4]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 4]);
for (var i = 3; i >= 1; i--)
{
_bodyPeriodTotal[i] += GetCandleRange(CandleSettingType.BodyShort, window[i]) -
GetCandleRange(CandleSettingType.BodyShort, window[i + _bodyShortAveragePeriod]);
}
_bodyPeriodTotal[0] += GetCandleRange(CandleSettingType.BodyLong, input) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyPeriodTotal = new decimal[5];
base.Reset();
}
}
}
@@ -0,0 +1,151 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Separating Lines candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: black (white) candle
/// - second candle: bullish(bearish) belt hold with the same open as the prior candle
/// The meaning of "long body" and "very short shadow" of the belt hold is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// The user should consider that separating lines is significant when coming in a trend and the belt hold has
/// the same direction of the trend, while this function does not consider it
/// </remarks>
public class SeparatingLines : CandlestickPattern
{
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private readonly int _equalAveragePeriod;
private decimal _shadowVeryShortPeriodTotal;
private decimal _bodyLongPeriodTotal;
private decimal _equalPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="SeparatingLines"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public SeparatingLines(string name)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.Equal).AveragePeriod) + 1 + 1)
{
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="SeparatingLines"/> class.
/// </summary>
public SeparatingLines()
: this("SEPARATINGLINES")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]);
}
return 0m;
}
decimal value;
if (
// opposite candles
(int)GetCandleColor(window[1]) == -(int)GetCandleColor(input) &&
// same open
input.Open <= window[1].Open + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1]) &&
input.Open >= window[1].Open - GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1]) &&
// belt hold: long body
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, input) &&
(
// with no lower shadow if bullish
(GetCandleColor(input) == CandleColor.White &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
)
||
// with no upper shadow if bearish
(GetCandleColor(input) == CandleColor.Black &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input)
)
)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod]);
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]) -
GetCandleRange(CandleSettingType.Equal, window[_equalAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowVeryShortPeriodTotal = 0m;
_bodyLongPeriodTotal = 0m;
_equalPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,143 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Shooting Star candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - small real body
/// - long upper shadow
/// - no, or very short, lower shadow
/// - gap up from prior real body
/// The meaning of "short", "very short" and "long" is specified with SetCandleSettings;
/// The returned value is negative(-1): shooting star is always bearish;
/// The user should consider that a shooting star must appear in an uptrend, while this function does not consider it
/// </remarks>
public class ShootingStar : CandlestickPattern
{
private readonly int _bodyShortAveragePeriod;
private readonly int _shadowLongAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private decimal _bodyShortPeriodTotal;
private decimal _shadowLongPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="ShootingStar"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ShootingStar(string name)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod),
CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod) + 1 + 1)
{
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
_shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ShootingStar"/> class.
/// </summary>
public ShootingStar()
: this("SHOOTINGSTAR")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
if (Samples >= Period - _shadowLongAveragePeriod)
{
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
return 0m;
}
decimal value;
if (
// small rb
GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// long upper shadow
GetUpperShadow(input) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, input) &&
// very short lower shadow
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) &&
// gap up
GetRealBodyGapUp(input, window[1])
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, input) -
GetCandleRange(CandleSettingType.ShadowLong, window[_shadowLongAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyShortPeriodTotal = 0;
_shadowLongPeriodTotal = 0;
_shadowVeryShortPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,121 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Short Line Candle candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - short real body
/// - short upper and lower shadow
/// The meaning of "short" is specified with SetCandleSettings
/// The returned value is positive(+1) when white, negative (-1) when black;
/// it does not mean bullish or bearish
/// </remarks>
public class ShortLineCandle : CandlestickPattern
{
private readonly int _bodyShortAveragePeriod;
private readonly int _shadowShortAveragePeriod;
private decimal _bodyShortPeriodTotal;
private decimal _shadowShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="ShortLineCandle"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ShortLineCandle(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowShort).AveragePeriod) + 1)
{
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
_shadowShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ShortLineCandle"/> class.
/// </summary>
public ShortLineCandle()
: this("SHORTLINECANDLE")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
if (Samples >= Period - _shadowShortAveragePeriod)
{
_shadowShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowShort, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowShort, _shadowShortPeriodTotal, input) &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowShort, _shadowShortPeriodTotal, input)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
_shadowShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowShort, input) -
GetCandleRange(CandleSettingType.ShadowShort, window[_shadowShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyShortPeriodTotal = 0m;
_shadowShortPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,108 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Spinning Top candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - small real body
/// - shadows longer than the real body
/// The meaning of "short" is specified with SetCandleSettings
/// The returned value is positive(+1) when white or negative(-1) when black;
/// it does not mean bullish or bearish
/// </remarks>
public class SpinningTop : CandlestickPattern
{
private readonly int _bodyShortAveragePeriod;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="SpinningTop"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public SpinningTop(string name)
: base(name, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod + 1)
{
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="SpinningTop"/> class.
/// </summary>
public SpinningTop()
: this("SPINNINGTOP")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
GetUpperShadow(input) > GetRealBody(input) &&
GetLowerShadow(input) > GetRealBody(input)
)
value = (int)GetCandleColor(input);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyShortPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,175 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Stalled Pattern candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - three white candlesticks with consecutively higher closes
/// - first candle: long white
/// - second candle: long white with no or very short upper shadow opening within or near the previous white real body
/// and closing higher than the prior candle
/// - third candle: small white that gaps away or "rides on the shoulder" of the prior long real body(= it's at
/// the upper end of the prior real body)
/// The meanings of "long", "very short", "short", "near" are specified with SetCandleSettings;
/// The returned value is negative(-1): stalled pattern is always bearish;
/// The user should consider that stalled pattern is significant when it appears in uptrend, while this function
/// does not consider it
/// </remarks>
public class StalledPattern : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _nearAveragePeriod;
private decimal[] _bodyLongPeriodTotal = new decimal[3];
private decimal _bodyShortPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
private decimal[] _nearPeriodTotal = new decimal[3];
/// <summary>
/// Initializes a new instance of the <see cref="StalledPattern"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public StalledPattern(string name)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod),
Math.Max(CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod, CandleSettings.Get(CandleSettingType.Near).AveragePeriod)) + 2 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="StalledPattern"/> class.
/// </summary>
public StalledPattern()
: this("STALLEDPATTERN")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal[2] += GetCandleRange(CandleSettingType.BodyLong, window[2]);
_bodyLongPeriodTotal[1] += GetCandleRange(CandleSettingType.BodyLong, window[1]);
}
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
}
if (Samples >= Period - _nearAveragePeriod)
{
_nearPeriodTotal[2] += GetCandleRange(CandleSettingType.Near, window[2]);
_nearPeriodTotal[1] += GetCandleRange(CandleSettingType.Near, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st white
GetCandleColor(window[2]) == CandleColor.White &&
// 2nd white
GetCandleColor(window[1]) == CandleColor.White &&
// 3rd white
GetCandleColor(input) == CandleColor.White &&
// consecutive higher closes
input.Close > window[1].Close && window[1].Close > window[2].Close &&
// 1st: long real body
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[2], window[2]) &&
// 2nd: long real body
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal[1], window[1]) &&
// very short upper shadow
GetUpperShadow(window[1]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, window[1]) &&
// opens within/near 1st real body
window[1].Open > window[2].Open &&
window[1].Open <= window[2].Close + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[2], window[2]) &&
// 3rd: small real body
GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// rides on the shoulder of 2nd real body
input.Open >= window[1].Close - GetRealBody(input) - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[1], window[1])
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 2; i >= 1; i--)
{
_bodyLongPeriodTotal[i] += GetCandleRange(CandleSettingType.BodyLong, window[i]) -
GetCandleRange(CandleSettingType.BodyLong, window[i + _bodyLongAveragePeriod]);
_nearPeriodTotal[i] += GetCandleRange(CandleSettingType.Near, window[i]) -
GetCandleRange(CandleSettingType.Near, window[i + _nearAveragePeriod]);
}
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_bodyShortAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = new decimal[3];
_bodyShortPeriodTotal = 0;
_shadowVeryShortPeriodTotal = 0;
_nearPeriodTotal = new decimal[3];
base.Reset();
}
}
}
@@ -0,0 +1,119 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Stick Sandwich candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: black candle
/// - second candle: white candle that trades only above the prior close(low > prior close)
/// - third candle: black candle with the close equal to the first candle's close
/// The meaning of "equal" is specified with SetCandleSettings
/// The returned value is always positive(+1): stick sandwich is always bullish;
/// The user should consider that stick sandwich is significant when coming in a downtrend,
/// while this function does not consider it
/// </remarks>
public class StickSandwich : CandlestickPattern
{
private readonly int _equalAveragePeriod;
private decimal _equalPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="StickSandwich"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public StickSandwich(string name)
: base(name, CandleSettings.Get(CandleSettingType.Equal).AveragePeriod + 2 + 1)
{
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="StickSandwich"/> class.
/// </summary>
public StickSandwich()
: this("STICKSANDWICH")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]);
}
return 0m;
}
decimal value;
if (
// first black
GetCandleColor(window[2]) == CandleColor.Black &&
// second white
GetCandleColor(window[1]) == CandleColor.White &&
// third black
GetCandleColor(input) == CandleColor.Black &&
// 2nd low > prior close
window[1].Low > window[2].Close &&
// 1st and 3rd same close
input.Close <= window[2].Close + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[2]) &&
input.Close >= window[2].Close - GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[2])
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[2]) -
GetCandleRange(CandleSettingType.Equal, window[_equalAveragePeriod + 2]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_equalPeriodTotal = 0m;
base.Reset();
}
}
}
+135
View File
@@ -0,0 +1,135 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Takuri (Dragonfly Doji with very long lower shadow) candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - doji body
/// - open and close at the high of the day = no or very short upper shadow
/// - very long lower shadow
/// The meaning of "doji", "very short" and "very long" is specified with SetCandleSettings
/// The returned value is always positive(+1) but this does not mean it is bullish: takuri must be considered
/// relatively to the trend
/// </remarks>
public class Takuri : CandlestickPattern
{
private readonly int _bodyDojiAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _shadowVeryLongAveragePeriod;
private decimal _bodyDojiPeriodTotal;
private decimal _shadowVeryShortPeriodTotal;
private decimal _shadowVeryLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="Takuri"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Takuri(string name)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod),
CandleSettings.Get(CandleSettingType.ShadowVeryLong).AveragePeriod) + 1)
{
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_shadowVeryLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Takuri"/> class.
/// </summary>
public Takuri()
: this("TAKURI")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyDojiAveragePeriod)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _shadowVeryLongAveragePeriod)
{
_shadowVeryLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryLong, input);
}
return 0m;
}
decimal value;
if (GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, input) &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal, input) &&
GetLowerShadow(input) > GetCandleAverage(CandleSettingType.ShadowVeryLong, _shadowVeryLongPeriodTotal, input)
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod]);
_shadowVeryShortPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryShort, input) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[_shadowVeryShortAveragePeriod]);
_shadowVeryLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowVeryLong, input) -
GetCandleRange(CandleSettingType.ShadowVeryLong, window[_shadowVeryLongAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyDojiPeriodTotal = 0m;
_shadowVeryShortPeriodTotal = 0m;
_shadowVeryLongPeriodTotal = 0m;
base.Reset();
}
}
}
+143
View File
@@ -0,0 +1,143 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Tasuki Gap candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - upside (downside) gap
/// - first candle after the window: white(black) candlestick
/// - second candle: black(white) candlestick that opens within the previous real body and closes under(above)
/// the previous real body inside the gap
/// - the size of two real bodies should be near the same
/// The meaning of "near" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// The user should consider that tasuki gap is significant when it appears in a trend, while this function does
/// not consider it
/// </remarks>
public class TasukiGap : CandlestickPattern
{
private readonly int _nearAveragePeriod;
private decimal _nearPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="TasukiGap"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public TasukiGap(string name)
: base(name, CandleSettings.Get(CandleSettingType.Near).AveragePeriod + 2 + 1)
{
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="TasukiGap"/> class.
/// </summary>
public TasukiGap()
: this("TASUKIGAP")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _nearAveragePeriod)
{
_nearPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]);
}
return 0m;
}
decimal value;
if (
(
// upside gap
GetRealBodyGapUp(window[1], window[2]) &&
// 1st: white
GetCandleColor(window[1]) == CandleColor.White &&
// 2nd: black
GetCandleColor(input) == CandleColor.Black &&
// that opens within the white rb
input.Open < window[1].Close && input.Open > window[1].Open &&
// and closes under the white rb
input.Close < window[1].Open &&
// inside the gap
input.Close > Math.Max(window[2].Close, window[2].Open) &&
// size of 2 rb near the same
Math.Abs(GetRealBody(window[1]) - GetRealBody(input)) < GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[1])
) ||
(
// downside gap
GetRealBodyGapDown(window[1], window[2]) &&
// 1st: black
GetCandleColor(window[1]) == CandleColor.Black &&
// 2nd: white
GetCandleColor(input) == CandleColor.White &&
// that opens within the black rb
input.Open < window[1].Open && input.Open > window[1].Close &&
// and closes above the black rb
input.Close > window[1].Open &&
// inside the gap
input.Close < Math.Min(window[2].Close, window[2].Open) &&
// size of 2 rb near the same
Math.Abs(GetRealBody(window[1]) - GetRealBody(input)) < GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal, window[1])
)
)
value = (int)GetCandleColor(window[1]);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_nearPeriodTotal += GetCandleRange(CandleSettingType.Near, window[1]) -
GetCandleRange(CandleSettingType.Near, window[_nearAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_nearPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,138 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Three Black Crows candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - three consecutive and declining black candlesticks
/// - each candle must have no or very short lower shadow
/// - each candle after the first must open within the prior candle's real body
/// - the first candle's close should be under the prior white candle's high
/// The meaning of "very short" is specified with SetCandleSettings
/// The returned value is negative (-1): three black crows is always bearish;
/// The user should consider that 3 black crows is significant when it appears after a mature advance or at high levels,
/// while this function does not consider it
/// </remarks>
public class ThreeBlackCrows : CandlestickPattern
{
private readonly int _shadowVeryShortAveragePeriod;
private decimal[] _shadowVeryShortPeriodTotal = new decimal[3];
/// <summary>
/// Initializes a new instance of the <see cref="ThreeBlackCrows"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ThreeBlackCrows(string name)
: base(name, CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod + 3 + 1)
{
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ThreeBlackCrows"/> class.
/// </summary>
public ThreeBlackCrows()
: this("THREEBLACKCROWS")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal[2] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[2]);
_shadowVeryShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
_shadowVeryShortPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
return 0m;
}
decimal value;
if (
// white
GetCandleColor(window[3]) == CandleColor.White &&
// 1st black
GetCandleColor(window[2]) == CandleColor.Black &&
// very short lower shadow
GetLowerShadow(window[2]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[2], window[2]) &&
// 2nd black
GetCandleColor(window[1]) == CandleColor.Black &&
// very short lower shadow
GetLowerShadow(window[1]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
// 3rd black
GetCandleColor(input) == CandleColor.Black &&
// very short lower shadow
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
// 2nd black opens within 1st black's rb
window[1].Open < window[2].Open && window[1].Open > window[2].Close &&
// 3rd black opens within 2nd black's rb
input.Open < window[1].Open && input.Open > window[1].Close &&
// 1st black closes under prior candle's high
window[3].High > window[2].Close &&
// three declining
window[2].Close > window[1].Close &&
// three declining
window[1].Close > input.Close
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 2; i >= 0; i--)
{
_shadowVeryShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[i]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[i + _shadowVeryShortAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowVeryShortPeriodTotal = new decimal[3];
base.Reset();
}
}
}
@@ -0,0 +1,133 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Three Inside Up/Down candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white(black) real body
/// - second candle: short real body totally engulfed by the first
/// - third candle: black(white) candle that closes lower(higher) than the first candle's open
/// The meaning of "short" and "long" is specified with SetCandleSettings
/// The returned value is positive (+1) for the three inside up or negative (-1) for the three inside down;
/// The user should consider that a three inside up is significant when it appears in a downtrend and a three inside
/// down is significant when it appears in an uptrend, while this function does not consider the trend
/// </remarks>
public class ThreeInside : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="ThreeInside"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ThreeInside(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 2 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ThreeInside"/> class.
/// </summary>
public ThreeInside()
: this("THREEINSIDE")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 2 && Samples < Period - 2)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyShortAveragePeriod - 1 && Samples < Period - 1)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// 2nd: short
GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, window[1]) &&
// engulfed by 1st
Math.Max(window[1].Close, window[1].Open) < Math.Max(window[2].Close, window[2].Open) &&
Math.Min(window[1].Close, window[1].Open) > Math.Min(window[2].Close, window[2].Open) &&
// 3rd: opposite to 1st
((GetCandleColor(window[2]) == CandleColor.White && GetCandleColor(input) == CandleColor.Black && input.Close < window[2].Open) ||
// and closing out
(GetCandleColor(window[2]) == CandleColor.Black && GetCandleColor(input) == CandleColor.White && input.Close > window[2].Open)
)
)
value = -(int)GetCandleColor(window[2]);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[2 + _bodyLongAveragePeriod]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, window[1]) -
GetCandleRange(CandleSettingType.BodyShort, window[1 + _bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_bodyShortPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,147 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Three Line Strike candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - three white soldiers (three black crows): three white (black) candlesticks with consecutively higher (lower) closes,
/// each opening within or near the previous real body
/// - fourth candle: black (white) candle that opens above (below) prior candle's close and closes below (above)
/// the first candle's open
/// The meaning of "near" is specified with SetCandleSettings;
/// The returned value is positive (+1) when bullish or negative (-1) when bearish;
/// The user should consider that 3-line strike is significant when it appears in a trend in the same direction of
/// the first three candles, while this function does not consider it
/// </remarks>
public class ThreeLineStrike : CandlestickPattern
{
private readonly int _nearAveragePeriod;
private decimal[] _nearPeriodTotal = new decimal[4];
/// <summary>
/// Initializes a new instance of the <see cref="ThreeLineStrike"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ThreeLineStrike(string name)
: base(name, CandleSettings.Get(CandleSettingType.Near).AveragePeriod + 3 + 1)
{
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ThreeLineStrike"/> class.
/// </summary>
public ThreeLineStrike()
: this("THREELINESTRIKE")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _nearAveragePeriod)
{
_nearPeriodTotal[3] += GetCandleRange(CandleSettingType.Near, window[3]);
_nearPeriodTotal[2] += GetCandleRange(CandleSettingType.Near, window[2]);
}
return 0m;
}
decimal value;
if (
// three with same color
GetCandleColor(window[3]) == GetCandleColor(window[2]) &&
GetCandleColor(window[2]) == GetCandleColor(window[1]) &&
// 4th opposite color
(int)GetCandleColor(input) == -(int)GetCandleColor(window[1]) &&
// 2nd opens within/near 1st rb
window[2].Open >= Math.Min(window[3].Open, window[3].Close) - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[3], window[3]) &&
window[2].Open <= Math.Max(window[3].Open, window[3].Close) + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[3], window[3]) &&
// 3rd opens within/near 2nd rb
window[1].Open >= Math.Min(window[2].Open, window[2].Close) - GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[2], window[2]) &&
window[1].Open <= Math.Max(window[2].Open, window[2].Close) + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[2], window[2]) &&
(
(
// if three white
GetCandleColor(window[1]) == CandleColor.White &&
// consecutive higher closes
window[1].Close > window[2].Close && window[2].Close > window[3].Close &&
// 4th opens above prior close
input.Open > window[1].Close &&
// 4th closes below 1st open
input.Close < window[3].Open
) ||
(
// if three black
GetCandleColor(window[1]) == CandleColor.Black &&
// consecutive lower closes
window[1].Close < window[2].Close && window[2].Close < window[3].Close &&
// 4th opens below prior close
input.Open < window[1].Close &&
// 4th closes above 1st open
input.Close > window[3].Open
)
)
)
value = (int)GetCandleColor(window[1]);
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 3; i >= 2; i--)
{
_nearPeriodTotal[i] += GetCandleRange(CandleSettingType.Near, window[i]) -
GetCandleRange(CandleSettingType.Near, window[i + _nearAveragePeriod]);
}
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_nearPeriodTotal = new decimal[4];
base.Reset();
}
}
}
@@ -0,0 +1,98 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Three Outside Up/Down candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first: black(white) real body
/// - second: white(black) real body that engulfs the prior real body
/// - third: candle that closes higher(lower) than the second candle
/// The returned value is positive (+1) for the three outside up or negative (-1) for the three outside down;
/// The user should consider that a three outside up must appear in a downtrend and three outside down must appear
/// in an uptrend, while this function does not consider it
/// </remarks>
public class ThreeOutside : CandlestickPattern
{
/// <summary>
/// Initializes a new instance of the <see cref="ThreeOutside"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ThreeOutside(string name)
: base(name, 3)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ThreeOutside"/> class.
/// </summary>
public ThreeOutside()
: this("THREEOUTSIDE")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
return 0m;
}
decimal value;
if (
(
// white engulfs black
GetCandleColor(window[1]) == CandleColor.White && GetCandleColor(window[2]) == CandleColor.Black &&
window[1].Close > window[2].Open && window[1].Open < window[2].Close &&
// third candle higher
input.Close > window[1].Close
)
||
(
// black engulfs white
GetCandleColor(window[1]) == CandleColor.Black && GetCandleColor(window[2]) == CandleColor.White &&
window[1].Open > window[2].Close && window[1].Close < window[2].Open &&
// third candle lower
input.Close < window[1].Close
)
)
value = (int)GetCandleColor(window[1]);
else
value = 0;
return value;
}
}
}
@@ -0,0 +1,178 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Three Stars In The South candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black candle with long lower shadow
/// - second candle: smaller black candle that opens higher than prior close but within prior candle's range
/// and trades lower than prior close but not lower than prior low and closes off of its low(it has a shadow)
/// - third candle: small black marubozu(or candle with very short shadows) engulfed by prior candle's range
/// The meanings of "long body", "short body", "very short shadow" are specified with SetCandleSettings;
/// The returned value is positive (+1): 3 stars in the south is always bullish;
/// The user should consider that 3 stars in the south is significant when it appears in downtrend, while this function
/// does not consider it
/// </remarks>
public class ThreeStarsInSouth : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _shadowLongAveragePeriod;
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _shadowLongPeriodTotal;
private decimal[] _shadowVeryShortPeriodTotal = new decimal[2];
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="ThreeStarsInSouth"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ThreeStarsInSouth(string name)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod, CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod),
Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod)) + 2 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_shadowLongAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowLong).AveragePeriod;
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ThreeStarsInSouth"/> class.
/// </summary>
public ThreeStarsInSouth()
: this("THREESTARSINSOUTH")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]);
}
if (Samples >= Period - _shadowLongAveragePeriod)
{
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, window[2]);
}
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
_shadowVeryShortPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st black
GetCandleColor(window[2]) == CandleColor.Black &&
// 2nd black
GetCandleColor(window[1]) == CandleColor.Black &&
// 3rd black
GetCandleColor(input) == CandleColor.Black &&
// 1st: long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// with long lower shadow
GetLowerShadow(window[2]) > GetCandleAverage(CandleSettingType.ShadowLong, _shadowLongPeriodTotal, window[2]) &&
// 2nd: smaller candle
GetRealBody(window[1]) < GetRealBody(window[2]) &&
// that opens higher but within 1st range
window[1].Open > window[2].Close && window[1].Open <= window[2].High &&
// and trades lower than 1st close
window[1].Low < window[2].Close &&
// but not lower than 1st low
window[1].Low >= window[2].Low &&
// and has a lower shadow
GetLowerShadow(window[1]) > GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
// 3rd: small marubozu
GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
GetLowerShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
// engulfed by prior candle's range
input.Low > window[1].Low && input.High < window[1].High
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[2 + _bodyLongAveragePeriod]);
_shadowLongPeriodTotal += GetCandleRange(CandleSettingType.ShadowLong, window[2]) -
GetCandleRange(CandleSettingType.ShadowLong, window[2 + _shadowLongAveragePeriod]);
for (var i = 1; i >= 0; i--)
{
_shadowVeryShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[i]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[i + _shadowVeryShortAveragePeriod]);
}
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_shadowLongPeriodTotal = 0;
_shadowVeryShortPeriodTotal = new decimal[2];
_bodyShortPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,189 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Three Advancing White Soldiers candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - three white candlesticks with consecutively higher closes
/// - Greg Morris wants them to be long, Steve Nison doesn't; anyway they should not be short
/// - each candle opens within or near the previous white real body
/// - each candle must have no or very short upper shadow
/// - to differentiate this pattern from advance block, each candle must not be far shorter than the prior candle
/// The meanings of "not short", "very short shadow", "far" and "near" are specified with SetCandleSettings;
/// here the 3 candles must be not short, if you want them to be long use SetCandleSettings on BodyShort;
/// The returned value is positive (+1): advancing 3 white soldiers is always bullish;
/// The user should consider that 3 white soldiers is significant when it appears in downtrend, while this function
/// does not consider it
/// </remarks>
public class ThreeWhiteSoldiers : CandlestickPattern
{
private readonly int _shadowVeryShortAveragePeriod;
private readonly int _nearAveragePeriod;
private readonly int _farAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal[] _shadowVeryShortPeriodTotal = new decimal[3];
private decimal[] _nearPeriodTotal = new decimal[3];
private decimal[] _farPeriodTotal = new decimal[3];
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="ThreeWhiteSoldiers"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public ThreeWhiteSoldiers(string name)
: base(name, Math.Max(Math.Max(CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod),
Math.Max(CandleSettings.Get(CandleSettingType.Far).AveragePeriod, CandleSettings.Get(CandleSettingType.Near).AveragePeriod)) + 2 + 1)
{
_shadowVeryShortAveragePeriod = CandleSettings.Get(CandleSettingType.ShadowVeryShort).AveragePeriod;
_nearAveragePeriod = CandleSettings.Get(CandleSettingType.Near).AveragePeriod;
_farAveragePeriod = CandleSettings.Get(CandleSettingType.Far).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="ThreeWhiteSoldiers"/> class.
/// </summary>
public ThreeWhiteSoldiers()
: this("THREEWHITESOLDIERS")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _shadowVeryShortAveragePeriod)
{
_shadowVeryShortPeriodTotal[2] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[2]);
_shadowVeryShortPeriodTotal[1] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[1]);
_shadowVeryShortPeriodTotal[0] += GetCandleRange(CandleSettingType.ShadowVeryShort, input);
}
if (Samples >= Period - _nearAveragePeriod)
{
_nearPeriodTotal[2] += GetCandleRange(CandleSettingType.Near, window[2]);
_nearPeriodTotal[1] += GetCandleRange(CandleSettingType.Near, window[1]);
}
if (Samples >= Period - _farAveragePeriod)
{
_farPeriodTotal[2] += GetCandleRange(CandleSettingType.Far, window[2]);
_farPeriodTotal[1] += GetCandleRange(CandleSettingType.Far, window[1]);
}
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st white
GetCandleColor(window[2]) == CandleColor.White &&
// very short upper shadow
GetUpperShadow(window[2]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[2], window[2]) &&
// 2nd white
GetCandleColor(window[1]) == CandleColor.White &&
// very short upper shadow
GetUpperShadow(window[1]) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[1], window[1]) &&
// 3rd white
GetCandleColor(input) == CandleColor.White &&
// very short upper shadow
GetUpperShadow(input) < GetCandleAverage(CandleSettingType.ShadowVeryShort, _shadowVeryShortPeriodTotal[0], input) &&
// consecutive higher closes
input.Close > window[1].Close && window[1].Close > window[2].Close &&
// 2nd opens within/near 1st real body
window[1].Open > window[2].Open &&
window[1].Open <= window[2].Close + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[2], window[2]) &&
// 3rd opens within/near 2nd real body
input.Open > window[1].Open &&
input.Open <= window[1].Close + GetCandleAverage(CandleSettingType.Near, _nearPeriodTotal[1], window[1]) &&
// 2nd not far shorter than 1st
GetRealBody(window[1]) > GetRealBody(window[2]) - GetCandleAverage(CandleSettingType.Far, _farPeriodTotal[2], window[2]) &&
// 3rd not far shorter than 2nd
GetRealBody(input) > GetRealBody(window[1]) - GetCandleAverage(CandleSettingType.Far, _farPeriodTotal[1], window[1]) &&
// not short real body
GetRealBody(input) > GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input)
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
for (var i = 2; i >= 0; i--)
{
_shadowVeryShortPeriodTotal[i] += GetCandleRange(CandleSettingType.ShadowVeryShort, window[i]) -
GetCandleRange(CandleSettingType.ShadowVeryShort, window[i + _shadowVeryShortAveragePeriod]);
}
for (var i = 2; i >= 1; i--)
{
_farPeriodTotal[i] += GetCandleRange(CandleSettingType.Far, window[i]) -
GetCandleRange(CandleSettingType.Far, window[i + _farAveragePeriod]);
}
for (var i = 2; i >= 1; i--)
{
_nearPeriodTotal[i] += GetCandleRange(CandleSettingType.Near, window[i]) -
GetCandleRange(CandleSettingType.Near, window[i + _nearAveragePeriod]);
}
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_shadowVeryShortPeriodTotal = new decimal[3];
_nearPeriodTotal = new decimal[3];
_farPeriodTotal = new decimal[3];
_bodyShortPeriodTotal = 0;
base.Reset();
}
}
}
+134
View File
@@ -0,0 +1,134 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Thrusting candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black candle
/// - second candle: white candle with open below previous day low and close into previous day body under the midpoint;
/// to differentiate it from in-neck the close should not be equal to the black candle's close
/// The meaning of "equal" is specified with SetCandleSettings
/// The returned value is negative(-1): thrusting pattern is always bearish
/// The user should consider that the thrusting pattern is significant when it appears in a downtrend and it could be
/// even bullish "when coming in an uptrend or occurring twice within several days" (Steve Nison says), while this
/// function does not consider the trend
/// </remarks>
public class Thrusting : CandlestickPattern
{
private readonly int _equalAveragePeriod;
private readonly int _bodyLongAveragePeriod;
private decimal _equalPeriodTotal;
private decimal _bodyLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="Thrusting"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Thrusting(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.Equal).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod) + 1 + 1)
{
_equalAveragePeriod = CandleSettings.Get(CandleSettingType.Equal).AveragePeriod;
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Thrusting"/> class.
/// </summary>
public Thrusting()
: this("THRUSTING")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _equalAveragePeriod)
{
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]);
}
if (Samples >= Period - _bodyLongAveragePeriod)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]);
}
return 0m;
}
decimal value;
if (
// 1st: black
GetCandleColor(window[1]) == CandleColor.Black &&
// long
GetRealBody(window[1]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[1]) &&
// 2nd: white
GetCandleColor(input) == CandleColor.White &&
// open below prior low
input.Open < window[1].Low &&
// close into prior body
input.Close > window[1].Close + GetCandleAverage(CandleSettingType.Equal, _equalPeriodTotal, window[1]) &&
// under the midpoint
input.Close <= window[1].Close + GetRealBody(window[1]) * 0.5m
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_equalPeriodTotal += GetCandleRange(CandleSettingType.Equal, window[1]) -
GetCandleRange(CandleSettingType.Equal, window[_equalAveragePeriod + 1]);
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[1]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_equalPeriodTotal = 0m;
_bodyLongPeriodTotal = 0m;
base.Reset();
}
}
}
+127
View File
@@ -0,0 +1,127 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Tristar candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - 3 consecutive doji days
/// - the second doji is a star
/// The meaning of "doji" is specified with SetCandleSettings
/// The returned value is positive(+1) when bullish or negative(-1) when bearish
/// </remarks>
public class Tristar : CandlestickPattern
{
private readonly int _bodyDojiAveragePeriod;
private decimal _bodyDojiPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="Tristar"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public Tristar(string name)
: base(name, CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod + 2 + 1)
{
_bodyDojiAveragePeriod = CandleSettings.Get(CandleSettingType.BodyDoji).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="Tristar"/> class.
/// </summary>
public Tristar()
: this("TRISTAR")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyDojiAveragePeriod - 2 && Samples < Period - 2)
{
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, input);
}
return 0m;
}
decimal value;
if (
// 1st: doji
GetRealBody(window[2]) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, window[2]) &&
// 2nd: doji
GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, window[2]) &&
// 3rd: doji
GetRealBody(input) <= GetCandleAverage(CandleSettingType.BodyDoji, _bodyDojiPeriodTotal, window[2]))
{
value = 0;
if (
// 2nd gaps up
GetRealBodyGapUp(window[1], window[2]) &&
// 3rd is not higher than 2nd
Math.Max(input.Open, input.Close) < Math.Max(window[1].Open, window[1].Close)
)
value = -1m;
if (
// 2nd gaps down
GetRealBodyGapDown(window[1], window[2]) &&
// 3rd is not lower than 2nd
Math.Min(input.Open, input.Close) > Math.Min(window[1].Open, window[1].Close)
)
value = 1m;
}
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyDojiPeriodTotal += GetCandleRange(CandleSettingType.BodyDoji, window[2]) -
GetCandleRange(CandleSettingType.BodyDoji, window[_bodyDojiAveragePeriod + 2]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyDojiPeriodTotal = 0m;
base.Reset();
}
}
}
+122
View File
@@ -0,0 +1,122 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Two Crows candlestick pattern indicator
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long white candle
/// - second candle: black real body
/// - gap between the first and the second candle's real bodies
/// - third candle: black candle that opens within the second real body and closes within the first real body
/// The meaning of "long" is specified with SetCandleSettings
/// The returned value is negative (-1): two crows is always bearish;
/// The user should consider that two crows is significant when it appears in an uptrend, while this function
/// does not consider the trend.
/// </remarks>
public class TwoCrows : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private decimal _bodyLongPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="TwoCrows"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public TwoCrows(string name)
: base(name, CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod + 2 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="TwoCrows"/> class.
/// </summary>
public TwoCrows()
: this("TWOCROWS")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 2 && Samples < Period - 2)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
return 0m;
}
decimal value;
if (
// 1st: white
GetCandleColor(window[2]) == CandleColor.White &&
// long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// 2nd: black
GetCandleColor(window[1]) == CandleColor.Black &&
// gapping up
GetRealBodyGapUp(window[1], window[2]) &&
// 3rd: black
GetCandleColor(input) == CandleColor.Black &&
// opening within 2nd rb
input.Open < window[1].Open && input.Open > window[1].Close &&
// closing within 1st rb
input.Close > window[2].Open && input.Close < window[2].Close
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[2 + _bodyLongAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0m;
base.Reset();
}
}
}
@@ -0,0 +1,137 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Unique Three River candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: long black candle
/// - second candle: black harami candle with a lower low than the first candle's low
/// - third candle: small white candle with open not lower than the second candle's low, better if its open and
/// close are under the second candle's close
/// The meaning of "short" and "long" is specified with SetCandleSettings
/// The returned value is positive(+1): unique 3 river is always bullish and should appear in a downtrend
/// to be significant, while this function does not consider the trend
/// </remarks>
public class UniqueThreeRiver : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="UniqueThreeRiver"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public UniqueThreeRiver(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod) + 2 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="UniqueThreeRiver"/> class.
/// </summary>
public UniqueThreeRiver()
: this("UNIQUETHREERIVER")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 2 && Samples < Period - 2)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyShortAveragePeriod)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st: long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// black
GetCandleColor(window[2]) == CandleColor.Black &&
// 2nd: black
GetCandleColor(window[1]) == CandleColor.Black &&
// harami
window[1].Close > window[2].Close && window[1].Open <= window[2].Open &&
// lower low
window[1].Low < window[2].Low &&
// 3rd: short
GetRealBody(input) < GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, input) &&
// white
GetCandleColor(input) == CandleColor.White &&
// open not lower
input.Open > window[1].Low
)
value = 1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 2]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_bodyShortPeriodTotal = 0;
base.Reset();
}
}
}
@@ -0,0 +1,108 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Up/Down Gap Three Methods candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: white (black) candle
/// - second candle: white(black) candle
/// - upside(downside) gap between the first and the second real bodies
/// - third candle: black(white) candle that opens within the second real body and closes within the first real body
/// The returned value is positive(+1) when bullish or negative(-1) when bearish;
/// The user should consider that up/downside gap 3 methods is significant when it appears in a trend, while this
/// function does not consider it
/// </remarks>
public class UpDownGapThreeMethods : CandlestickPattern
{
/// <summary>
/// Initializes a new instance of the <see cref="UpDownGapThreeMethods"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public UpDownGapThreeMethods(string name)
: base(name, 2 + 1)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="UpDownGapThreeMethods"/> class.
/// </summary>
public UpDownGapThreeMethods()
: this("UPDOWNGAPTHREEMETHODS")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
return 0m;
}
decimal value;
if (
// 1st and 2nd of same color
GetCandleColor(window[2]) == GetCandleColor(window[1]) &&
// 3rd opposite color
(int)GetCandleColor(window[1]) == -(int)GetCandleColor(input) &&
// 3rd opens within 2nd rb
input.Open < Math.Max(window[1].Close, window[1].Open) &&
input.Open > Math.Min(window[1].Close, window[1].Open) &&
// 3rd closes within 1st rb
input.Close < Math.Max(window[2].Close, window[2].Open) &&
input.Close > Math.Min(window[2].Close, window[2].Open) &&
((
// when 1st is white
GetCandleColor(window[2]) == CandleColor.White &&
// upside gap
GetRealBodyGapUp(window[1], window[2])
) ||
(
// when 1st is black
GetCandleColor(window[2]) == CandleColor.Black &&
// downside gap
GetRealBodyGapDown(window[1], window[2])
)
)
)
value = (int)GetCandleColor(window[2]);
else
value = 0;
return value;
}
}
}
@@ -0,0 +1,139 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators.CandlestickPatterns
{
/// <summary>
/// Upside Gap Two Crows candlestick pattern
/// </summary>
/// <remarks>
/// Must have:
/// - first candle: white candle, usually long
/// - second candle: small black real body
/// - gap between the first and the second candle's real bodies
/// - third candle: black candle with a real body that engulfs the preceding candle
/// and closes above the white candle's close
/// The meaning of "short" and "long" is specified with SetCandleSettings
/// The returned value is negative(-1): upside gap two crows is always bearish;
/// The user should consider that an upside gap two crows is significant when it appears in an uptrend,
/// while this function does not consider the trend
/// </remarks>
public class UpsideGapTwoCrows : CandlestickPattern
{
private readonly int _bodyLongAveragePeriod;
private readonly int _bodyShortAveragePeriod;
private decimal _bodyLongPeriodTotal;
private decimal _bodyShortPeriodTotal;
/// <summary>
/// Initializes a new instance of the <see cref="UpsideGapTwoCrows"/> class using the specified name.
/// </summary>
/// <param name="name">The name of this indicator</param>
public UpsideGapTwoCrows(string name)
: base(name, Math.Max(CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod, CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod) + 2 + 1)
{
_bodyLongAveragePeriod = CandleSettings.Get(CandleSettingType.BodyLong).AveragePeriod;
_bodyShortAveragePeriod = CandleSettings.Get(CandleSettingType.BodyShort).AveragePeriod;
}
/// <summary>
/// Initializes a new instance of the <see cref="UpsideGapTwoCrows"/> class.
/// </summary>
public UpsideGapTwoCrows()
: this("UPSIDEGAPTWOCROWS")
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Samples >= Period; }
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="window">The window of data held in this indicator</param>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IBaseDataBar> window, IBaseDataBar input)
{
if (!IsReady)
{
if (Samples >= Period - _bodyLongAveragePeriod - 2 && Samples < Period - 2)
{
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, input);
}
if (Samples >= Period - _bodyShortAveragePeriod - 1 && Samples < Period - 1)
{
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, input);
}
return 0m;
}
decimal value;
if (
// 1st: white
GetCandleColor(window[2]) == CandleColor.White &&
// long
GetRealBody(window[2]) > GetCandleAverage(CandleSettingType.BodyLong, _bodyLongPeriodTotal, window[2]) &&
// 2nd: black
GetCandleColor(window[1]) == CandleColor.Black &&
// short
GetRealBody(window[1]) <= GetCandleAverage(CandleSettingType.BodyShort, _bodyShortPeriodTotal, window[1]) &&
// gapping up
GetRealBodyGapUp(window[1], window[2]) &&
// 3rd: black
GetCandleColor(input) == CandleColor.Black &&
// 3rd: engulfing prior rb
input.Open > window[1].Open && input.Close < window[1].Close &&
// closing above 1st
input.Close > window[2].Close
)
value = -1m;
else
value = 0m;
// add the current range and subtract the first range: this is done after the pattern recognition
// when avgPeriod is not 0, that means "compare with the previous candles" (it excludes the current candle)
_bodyLongPeriodTotal += GetCandleRange(CandleSettingType.BodyLong, window[2]) -
GetCandleRange(CandleSettingType.BodyLong, window[_bodyLongAveragePeriod + 2]);
_bodyShortPeriodTotal += GetCandleRange(CandleSettingType.BodyShort, window[1]) -
GetCandleRange(CandleSettingType.BodyShort, window[_bodyShortAveragePeriod + 1]);
return value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_bodyLongPeriodTotal = 0;
_bodyShortPeriodTotal = 0;
base.Reset();
}
}
}
+104
View File
@@ -0,0 +1,104 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Chaikin Money Flow Index (CMF) is a volume-weighted average of accumulation and distribution over
/// a specified period.
///
/// CMF = n-day Sum of [(((C - L) - (H - C)) / (H - L)) x Vol] / n-day Sum of Vol
///
/// Where:
/// n = number of periods, typically 21
/// H = high
/// L = low
/// C = close
/// Vol = volume
///
/// https://www.fidelity.com/learning-center/trading-investing/technical-analysis/technical-indicator-guide/cmf
/// </summary>
public class ChaikinMoneyFlow : TradeBarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Holds the point-wise flow-sum and volume terms.
/// </summary>
private readonly Sum _flowRatioSum;
private readonly Sum _volumeSum;
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _flowRatioSum.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_volumeSum.Reset();
_flowRatioSum.Reset();
base.Reset();
}
/// <summary>
/// Initializes a new instance of the ChaikinMoneyFlow class
/// </summary>
/// <param name="name">A name for the indicator</param>
/// <param name="period">The period over which to perform computation</param>
public ChaikinMoneyFlow(string name, int period)
: base(name)
{
WarmUpPeriod = period;
_flowRatioSum = new Sum(period);
_volumeSum = new Sum(period);
}
/// <summary>
/// Initializes a new instance of the ChaikinMoneyFlow class
/// </summary>
/// <param name="period">The period over which to perform computation</param>
public ChaikinMoneyFlow(int period)
: this($"CMF({period})", period)
{
}
/// <summary>
/// Computes the next value for this indicator from the given state.
/// </summary>
/// <param name="input">The input value to this indicator on this time step</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(TradeBar input)
{
var denominator = (input.High - input.Low);
var flowRatio = denominator > 0
? input.Volume * (input.Close - input.Low - (input.High - input.Close)) / denominator
: 0m;
_flowRatioSum.Update(input.EndTime, flowRatio);
_volumeSum.Update(input.EndTime, input.Volume);
return !IsReady || _volumeSum == 0m ? 0m : _flowRatioSum / _volumeSum;
}
}
}
+44
View File
@@ -0,0 +1,44 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Indicators
{
/// <summary>
/// This class is an alias for AccumulationDistributionOscillator (also known as Chaikin Oscillator).
/// </summary>
public class ChaikinOscillator : AccumulationDistributionOscillator
{
/// <summary>
/// Initializes a new instance of the <see cref="ChaikinOscillator"/> class using the specified parameters
/// </summary>
/// <param name="fastPeriod">The fast moving average period</param>
/// <param name="slowPeriod">The slow moving average period</param>
public ChaikinOscillator(int fastPeriod, int slowPeriod)
: base($"ChaikinOscillator({fastPeriod},{slowPeriod})", fastPeriod, slowPeriod)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ChaikinOscillator"/> class with a custom name
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="fastPeriod">The fast moving average period</param>
/// <param name="slowPeriod">The slow moving average period</param>
public ChaikinOscillator(string name, int fastPeriod, int slowPeriod)
: base(name, fastPeriod, slowPeriod)
{
}
}
}
+120
View File
@@ -0,0 +1,120 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the short stop and lower stop values of the Chande Kroll Stop Indicator.
/// It is used to determine the optimal placement of a stop-loss order.
/// </summary>
public class ChandeKrollStop : BarIndicator, IIndicatorWarmUpPeriodProvider
{
private readonly AverageTrueRange _atr;
private readonly decimal _atrMult;
private readonly Maximum _underlyingMaximum;
private readonly Minimum _underlyingMinimum;
/// <summary>
/// Gets the short stop of ChandeKrollStop.
/// </summary>
public IndicatorBase<IndicatorDataPoint> ShortStop { get; }
/// <summary>
/// Gets the long stop of ChandeKrollStop.
/// </summary>
public IndicatorBase<IndicatorDataPoint> LongStop { get; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => Samples >= WarmUpPeriod;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Initializes a new instance of the <see cref="ChandeKrollStop"/> class.
/// </summary>
/// <param name="atrPeriod">The period over which to compute the average true range.</param>
/// <param name="atrMult">The ATR multiplier to be used to compute stops distance.</param>
/// <param name="period">The period over which to compute the max of high stop and min of low stop.</param>
/// <param name="movingAverageType">The type of smoothing used to smooth the true range values</param>
public ChandeKrollStop(int atrPeriod, decimal atrMult, int period, MovingAverageType movingAverageType = MovingAverageType.Wilders)
: this($"CKS({atrPeriod},{atrMult},{period})", atrPeriod, atrMult, period, movingAverageType)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ChandeKrollStop"/> class.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="atrPeriod">The period over which to compute the average true range.</param>
/// <param name="atrMult">The ATR multiplier to be used to compute stops distance.</param>
/// <param name="period">The period over which to compute the max of high stop and min of low stop.</param>
/// <param name="movingAverageType">The type of smoothing used to smooth the true range values</param>
public ChandeKrollStop(string name, int atrPeriod, decimal atrMult, int period, MovingAverageType movingAverageType = MovingAverageType.Wilders)
: base(name)
{
WarmUpPeriod = atrPeriod + period - 1;
_atr = new AverageTrueRange(atrPeriod, movingAverageType);
_atrMult = atrMult;
_underlyingMaximum = new Maximum(atrPeriod);
_underlyingMinimum = new Minimum(atrPeriod);
LongStop = new Minimum(name + "_Long", period);
ShortStop = new Maximum(name + "_Short", period);
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>The input is returned unmodified.</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
_atr.Update(input);
_underlyingMaximum.Update(input.EndTime, input.High);
var highStop = _underlyingMaximum.Current.Value - _atr.Current.Value * _atrMult;
_underlyingMinimum.Update(input.EndTime, input.Low);
var lowStop = _underlyingMinimum.Current.Value + _atr.Current.Value * _atrMult;
ShortStop.Update(input.EndTime, highStop);
LongStop.Update(input.EndTime, lowStop);
return input.Value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
base.Reset();
_atr.Reset();
_underlyingMaximum.Reset();
_underlyingMinimum.Reset();
ShortStop.Reset();
LongStop.Reset();
}
}
}
+110
View File
@@ -0,0 +1,110 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the Chande Momentum Oscillator (CMO).
/// CMO calculation is mostly identical to RSI.
/// The only difference is in the last step of calculation:
/// RSI = gain / (gain+loss)
/// CMO = (gain-loss) / (gain+loss)
/// </summary>
public class ChandeMomentumOscillator : WindowIndicator<IndicatorDataPoint>, IIndicatorWarmUpPeriodProvider
{
private decimal _prevValue;
private decimal _prevGain;
private decimal _prevLoss;
/// <summary>
/// Initializes a new instance of the <see cref="ChandeMomentumOscillator"/> class using the specified period.
/// </summary>
/// <param name="period">The period of the indicator</param>
public ChandeMomentumOscillator(int period)
: this($"CMO({period})", period)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ChandeMomentumOscillator"/> class using the specified name and period.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of the indicator</param>
public ChandeMomentumOscillator(string name, int period)
: base(name, period)
{
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => Samples > Period;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod => 1 + Period;
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <param name="window">The window for the input history</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IReadOnlyWindow<IndicatorDataPoint> window, IndicatorDataPoint input)
{
if (Samples == 1)
{
_prevValue = input.Value;
return 0m;
}
var difference = input.Value - _prevValue;
_prevValue = input.Value;
if (Samples > Period + 1)
{
_prevLoss *= (Period - 1);
_prevGain *= (Period - 1);
}
if (difference < 0)
_prevLoss -= difference;
else
_prevGain += difference;
if (!IsReady)
return 0m;
_prevLoss /= Period;
_prevGain /= Period;
var sum = _prevGain + _prevLoss;
return sum != 0 ? 100m * ((_prevGain - _prevLoss) / sum) : 0m;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_prevValue = 0;
_prevGain = 0;
_prevLoss = 0;
base.Reset();
}
}
}
+135
View File
@@ -0,0 +1,135 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// The ChoppinessIndex indicator is an indicator designed to determine if the market is choppy (trading sideways)
/// or not choppy (trading within a trend in either direction)
/// </summary>
public class ChoppinessIndex : BarIndicator, IIndicatorWarmUpPeriodProvider
{
private readonly int _period;
private readonly RollingWindow<decimal> _highs;
private readonly RollingWindow<decimal> _lows;
private readonly IndicatorBase<IBaseDataBar> _trueRange;
private readonly RollingWindow<decimal> _trueRangeHistory;
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => Samples >= WarmUpPeriod;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Creates a new ChoppinessIndex indicator using the specified period and moving average type
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period used for rolling windows for highs and lows</param>
public ChoppinessIndex(string name, int period)
: base(name)
{
_period = period;
_trueRange = new TrueRange();
_trueRangeHistory = new RollingWindow<decimal>(period);
_highs = new RollingWindow<decimal>(period);
_lows = new RollingWindow<decimal>(period);
WarmUpPeriod = period;
}
/// <summary>
/// Creates a new ChoppinessIndex indicator using the specified period
/// </summary>
/// <param name="period">The period used for rolling windows for highs and lows</param>
public ChoppinessIndex(int period)
: this($"CHOP({period})", period)
{
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
// compute the true range
_trueRange.Update(input);
// store candle high and low
_highs.Add(input.High);
_lows.Add(input.Low);
// store true range in rolling window
if (_trueRange.IsReady)
{
_trueRangeHistory.Add(_trueRange.Current.Value);
}
else
{
_trueRangeHistory.Add(input.High - input.Low);
}
if (IsReady)
{
// calculate max high and min low
var maxHigh = _highs.Max();
var minLow = _lows.Min();
if (maxHigh != minLow)
{
// return CHOP index
return (decimal)(100.0 * Math.Log10(((double) _trueRangeHistory.Sum()) / ((double) (maxHigh - minLow))) / Math.Log10(_period));
}
else
{
// situation of maxHigh = minLow represents a totally "choppy" or stagnant market,
// with no price movement at all.
// It's the extreme case of consolidation, hence the maximum value of 100 for the index
return 100m;
}
}
else
{
// return 0 when indicator is not ready
return 0m;
}
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_trueRange.Reset();
_trueRangeHistory.Reset();
_highs.Reset();
_lows.Reset();
base.Reset();
}
}
}
+122
View File
@@ -0,0 +1,122 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// Represents the traditional commodity channel index (CCI)
///
/// CCI = (Typical Price - 20-period SMA of TP) / (.015 * Mean Deviation)
/// Typical Price (TP) = (High + Low + Close)/3
/// Constant = 0.015
///
/// There are four steps to calculating the Mean Deviation, first, subtract
/// the most recent 20-period average of the typical price from each period's
/// typical price. Second, take the absolute values of these numbers. Third,
/// sum the absolute values. Fourth, divide by the total number of periods (20).
/// </summary>
public class CommodityChannelIndex : BarIndicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// This constant is used to ensure that CCI values fall between +100 and -100, 70% to 80% of the time
/// </summary>
private const decimal K = 0.015m;
/// <summary>
/// Gets the type of moving average
/// </summary>
public MovingAverageType MovingAverageType { get; }
/// <summary>
/// Keep track of the simple moving average of the typical price
/// </summary>
public IndicatorBase<IndicatorDataPoint> TypicalPriceAverage { get; }
/// <summary>
/// Keep track of the mean absolute deviation of the typical price
/// </summary>
public IndicatorBase<IndicatorDataPoint> TypicalPriceMeanDeviation { get; }
/// <summary>
/// Initializes a new instance of the CommodityChannelIndex class
/// </summary>
/// <param name="period">The period of the standard deviation and moving average (middle band)</param>
/// <param name="movingAverageType">The type of moving average to be used</param>
public CommodityChannelIndex(int period, MovingAverageType movingAverageType = MovingAverageType.Simple)
: this($"CCI({period})", period, movingAverageType)
{
}
/// <summary>
/// Initializes a new instance of the CommodityChannelIndex class
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of the standard deviation and moving average (middle band)</param>
/// <param name="movingAverageType">The type of moving average to be used</param>
public CommodityChannelIndex(string name, int period, MovingAverageType movingAverageType = MovingAverageType.Simple)
: base(name)
{
WarmUpPeriod = period;
MovingAverageType = movingAverageType;
TypicalPriceAverage = movingAverageType.AsIndicator(name + "_TypicalPriceAvg", period);
TypicalPriceMeanDeviation = new MeanAbsoluteDeviation(name + "_TypicalPriceMAD", period);
}
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => TypicalPriceAverage.IsReady && TypicalPriceMeanDeviation.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IBaseDataBar input)
{
var typicalPrice = (input.High + input.Low + input.Close) / 3.0m;
TypicalPriceAverage.Update(input.EndTime, typicalPrice);
TypicalPriceMeanDeviation.Update(input.EndTime, typicalPrice);
// compare this to zero, since if the mean deviation is very small we can get
// precision errors due to non-floating point math
var weightedMeanDeviation = K * TypicalPriceMeanDeviation.Current.Value;
if (weightedMeanDeviation == 0.0m)
{
return 0.0m;
}
return (typicalPrice - TypicalPriceAverage.Current.Value).SafeDivision(weightedMeanDeviation, Current.Value);
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
TypicalPriceAverage.Reset();
TypicalPriceMeanDeviation.Reset();
base.Reset();
}
}
}
+216
View File
@@ -0,0 +1,216 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using Python.Runtime;
using QuantConnect.Data;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator is capable of wiring up two separate indicators into a single indicator
/// such that the output of each will be sent to a user specified function.
/// </summary>
/// <remarks>
/// This type is initialized such that there is no need to call the Update function. This indicator
/// will have its values automatically updated each time a new piece of data is received from both
/// the left and right indicators.
/// </remarks>
public class CompositeIndicator : IndicatorBase<IndicatorDataPoint>
{
/// <summary>
/// Delegate type used to compose the output of two indicators into a new value.
/// </summary>
/// <remarks>
/// A simple example would be to compute the difference between the two indicators (such as with MACD)
/// (left, right) => left - right
/// </remarks>
/// <param name="left">The left indicator</param>
/// <param name="right">The right indicator</param>
/// <returns>And indicator result representing the composition of the two indicators</returns>
public delegate IndicatorResult IndicatorComposer(IndicatorBase left, IndicatorBase right);
/// <summary>function used to compose the individual indicators</summary>
private readonly IndicatorComposer _composer;
/// <summary>
/// Gets the 'left' indicator for the delegate
/// </summary>
public IndicatorBase Left { get; private set; }
/// <summary>
/// Gets the 'right' indicator for the delegate
/// </summary>
public IndicatorBase Right { get; private set; }
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady
{
get { return Left.IsReady && Right.IsReady; }
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
Left.Reset();
Right.Reset();
base.Reset();
}
/// <summary>
/// Creates a new CompositeIndicator capable of taking the output from the left and right indicators
/// and producing a new value via the composer delegate specified
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="left">The left indicator for the 'composer'</param>
/// <param name="right">The right indicator for the 'composer'</param>
/// <param name="composer">Function used to compose the left and right indicators</param>
public CompositeIndicator(string name, IndicatorBase left, IndicatorBase right, IndicatorComposer composer)
: base(name)
{
_composer = composer;
Left = left;
Right = right;
Name ??= $"COMPOSE({Left.Name},{Right.Name})";
ConfigureEventHandlers();
}
/// <summary>
/// Creates a new CompositeIndicator capable of taking the output from the left and right indicators
/// and producing a new value via the composer delegate specified
/// </summary>
/// <param name="left">The left indicator for the 'composer'</param>
/// <param name="right">The right indicator for the 'composer'</param>
/// <param name="composer">Function used to compose the left and right indicators</param>
public CompositeIndicator(IndicatorBase left, IndicatorBase right, IndicatorComposer composer)
: this(null, left, right, composer)
{ }
/// <summary>
/// Initializes a new instance of <see cref="CompositeIndicator"/> using two indicators
/// and a custom function.
/// </summary>
/// <param name="name">The name of the composite indicator.</param>
/// <param name="left">The first indicator in the composition.</param>
/// <param name="right">The second indicator in the composition.</param>
/// <param name="handler">A Python function that processes the indicator values.</param>
/// <exception cref="ArgumentException">
/// Thrown if the provided left or right indicator is not a valid QuantConnect Indicator object.
/// </exception>
public CompositeIndicator(string name, PyObject left, PyObject right, PyObject handler)
: this(
name,
(IndicatorBase)left.GetIndicatorAsManagedObject(),
(IndicatorBase)right.GetIndicatorAsManagedObject(),
new IndicatorComposer(handler.SafeAs<Func<IndicatorBase, IndicatorBase, IndicatorResult>>())
)
{
}
/// <summary>
/// Initializes a new instance of <see cref="CompositeIndicator"/> using two indicators
/// and a custom function.
/// </summary>
/// <param name="left">The first indicator in the composition.</param>
/// <param name="right">The second indicator in the composition.</param>
/// <param name="handler">A Python function that processes the indicator values.</param>
public CompositeIndicator(PyObject left, PyObject right, PyObject handler)
: this(null, left, right, handler)
{ }
/// <summary>
/// Computes the next value of this indicator from the given state
/// and returns an instance of the <see cref="IndicatorResult"/> class
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>An IndicatorResult object including the status of the indicator</returns>
protected override IndicatorResult ValidateAndComputeNextValue(IndicatorDataPoint input)
{
return _composer.Invoke(Left, Right);
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <remarks>
/// Since this class overrides <see cref="ValidateAndComputeNextValue"/>, this method is a no-op
/// </remarks>
/// <param name="_">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IndicatorDataPoint _)
{
// this should never actually be invoked
return _composer.Invoke(Left, Right).Value;
}
/// <summary>
/// Configures the event handlers for Left.Updated and Right.Updated to update this instance when
/// they both have new data.
/// </summary>
private void ConfigureEventHandlers()
{
// if either of these are constants then there's no reason
bool leftIsConstant = Left.GetType().IsSubclassOfGeneric(typeof(ConstantIndicator<>));
bool rightIsConstant = Right.GetType().IsSubclassOfGeneric(typeof(ConstantIndicator<>));
// wire up the Updated events such that when we get a new piece of data from both left and right
// we'll call update on this indicator. It's important to note that the CompositeIndicator only uses
// the timestamp that gets passed into the Update function, his compuation is soley a function
// of the left and right indicator via '_composer'
IndicatorDataPoint newLeftData = null;
IndicatorDataPoint newRightData = null;
Left.Updated += (sender, updated) =>
{
newLeftData = updated;
// if we have left and right data (or if right is a constant) then we need to update
if (newRightData != null || rightIsConstant)
{
var dataPoint = new IndicatorDataPoint { Time = MaxTime(updated) };
Update(dataPoint);
// reset these to null after each update
newLeftData = null;
newRightData = null;
}
};
Right.Updated += (sender, updated) =>
{
newRightData = updated;
// if we have left and right data (or if left is a constant) then we need to update
if (newLeftData != null || leftIsConstant)
{
var dataPoint = new IndicatorDataPoint { Time = MaxTime(updated) };
Update(dataPoint);
// reset these to null after each update
newLeftData = null;
newRightData = null;
}
};
}
private DateTime MaxTime(IndicatorDataPoint updated)
{
return new DateTime(Math.Max(updated.Time.Ticks, Math.Max(Right.Current.Time.Ticks, Left.Current.Time.Ticks)));
}
}
}
+181
View File
@@ -0,0 +1,181 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Linq;
namespace QuantConnect.Indicators
{
/// <summary>
/// Represents the Connors Relative Strength Index (CRSI), a combination of
/// the traditional Relative Strength Index (RSI), a Streak RSI (SRSI), and
/// Percent Rank.
/// This index is designed to provide a more robust measure of market strength
/// by combining momentum, streak behavior, and price change.
/// </summary>
public class ConnorsRelativeStrengthIndex : Indicator, IIndicatorWarmUpPeriodProvider
{
/// <summary>
/// Computes the traditional Relative Strength Index (RSI).
/// </summary>
private readonly RelativeStrengthIndex _rsi;
/// <summary>
/// Computes the RSI based on consecutive price streaks (SRSI).
/// </summary>
private readonly RelativeStrengthIndex _srsi;
/// <summary>
/// Stores recent price change ratios for calculating the Percent Rank.
/// </summary>
private readonly RollingWindow<decimal> _priceChangeRatios;
/// <summary>
/// Tracks the current trend streak (positive or negative) of price movements.
/// </summary>
private int _trendStreak;
/// <summary>
/// Stores the previous input data point.
/// </summary>
private IndicatorDataPoint _previousInput;
/// <summary>
/// Initializes a new instance of the <see cref="ConnorsRelativeStrengthIndex"/> class.
/// </summary>
/// <param name="name">The name of the indicator instance.</param>
/// <param name="rsiPeriod">The period for the RSI calculation.</param>
/// <param name="rsiPeriodStreak">The period for the Streak RSI calculation.</param>
/// <param name="lookBackPeriod">The period for calculating the Percent Rank.</param>
public ConnorsRelativeStrengthIndex(string name, int rsiPeriod, int rsiPeriodStreak, int lookBackPeriod) : base(name)
{
_rsi = new RelativeStrengthIndex(rsiPeriod);
_srsi = new RelativeStrengthIndex(rsiPeriodStreak);
_priceChangeRatios = new RollingWindow<decimal>(lookBackPeriod);
_trendStreak = 0;
WarmUpPeriod = Math.Max(lookBackPeriod, Math.Max(_rsi.WarmUpPeriod, _srsi.WarmUpPeriod));
}
/// <summary>
/// Initializes a new instance of the ConnorsRelativeStrengthIndex with specified RSI, Streak RSI,
/// and lookBack periods, using a default name format based on the provided parameters.
/// </summary>
public ConnorsRelativeStrengthIndex(int rsiPeriod, int rsiPeriodStreak, int rocPeriod)
: this($"CRSI({rsiPeriod},{rsiPeriodStreak},{rocPeriod})", rsiPeriod, rsiPeriodStreak, rocPeriod)
{
}
/// <summary>
/// Gets a value indicating whether the indicator is ready for use.
/// The indicator is ready when all its components (RSI, SRSI, and PriceChangeRatios) are ready.
/// </summary>
public override bool IsReady => _rsi.IsReady && _srsi.IsReady && _priceChangeRatios.IsReady;
/// <summary>
/// Gets the warm-up period required for the indicator to be ready.
/// This is the maximum period of all components (RSI, SRSI, and PriceChangeRatios).
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Computes the next value for the Connors Relative Strength Index (CRSI) based on the latest input data point.
/// The CRSI is calculated as the average of the traditional RSI, Streak RSI, and Percent Rank.
/// </summary>
/// <param name="input">The current input data point (typically the price data for the current period).</param>
/// <returns>The computed CRSI value, which combines the RSI, Streak RSI, and Percent Rank into a single value.
/// Returns zero if the indicator is not yet ready.</returns>
protected override decimal ComputeNextValue(IndicatorDataPoint input)
{
// RSI
_rsi.Update(input);
ComputeTrendStreak(input);
_srsi.Update(new IndicatorDataPoint(input.EndTime, _trendStreak));
if (_previousInput == null || _previousInput.Value == 0)
{
_previousInput = input;
_priceChangeRatios.Add(0m);
return decimal.Zero;
}
// PercentRank
var relativeMagnitude = 0m;
var priceChangeRatio = (input.Value - _previousInput.Value) / _previousInput.Value;
// Calculate PercentRank using only the previous values (exclude the current priceChangeRatio)
if (_priceChangeRatios.IsReady)
{
relativeMagnitude = 100m * _priceChangeRatios.Count(x => x < priceChangeRatio) / _priceChangeRatios.Count;
}
// Add the current priceChangeRatio to the rolling window for future calculations
_priceChangeRatios.Add(priceChangeRatio);
_previousInput = input;
// CRSI
if (IsReady)
{
// Calculate the CRSI only if all components are ready
return (_rsi.Current.Value + _srsi.Current.Value + relativeMagnitude) / 3;
}
// If not ready, return 0
return decimal.Zero;
}
/// <summary>
/// Updates the trend streak based on the price change direction between the current and previous input.
/// Resets the streak if the direction changes, otherwise increments or decrements it.
/// </summary>
/// <param name="input">The current input data point with price information.</param>
private void ComputeTrendStreak(IndicatorDataPoint input)
{
if (_previousInput == null)
{
return;
}
var change = input.Value - _previousInput.Value;
// If the price changes direction (up to down or down to up), reset the trend streak
if ((_trendStreak > 0 && change < 0) || (_trendStreak < 0 && change > 0))
{
_trendStreak = 0;
}
// Increment or decrement the trend streak based on price change direction
if (change > 0)
{
_trendStreak++;
}
else if (change < 0)
{
_trendStreak--;
}
}
/// <summary>
/// Resets the indicator to its initial state. This clears all internal data and resets
/// the RSI, Streak RSI, and PriceChangeRatios, as well as the trend streak counter.
/// </summary>
public override void Reset()
{
_rsi.Reset();
_srsi.Reset();
_priceChangeRatios.Reset();
_trendStreak = 0;
base.Reset();
}
}
}
+71
View File
@@ -0,0 +1,71 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data;
namespace QuantConnect.Indicators
{
/// <summary>
/// An indicator that will always return the same value.
/// </summary>
/// <typeparam name="T">The type of input this indicator takes</typeparam>
public sealed class ConstantIndicator<T> : IndicatorBase<T>
where T : IBaseData
{
private readonly decimal _value;
/// <summary>
/// Gets true since the ConstantIndicator is always ready to return the same value
/// </summary>
public override bool IsReady => true;
/// <summary>
/// Creates a new ConstantIndicator that will always return the specified value
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="value">The constant value to be returned</param>
public ConstantIndicator(string name, decimal value)
: base(name)
{
_value = value;
// set this immediately so it always has the .Value property correctly set,
// the time will be updated anytime this indicators Update method gets called.
Current = new IndicatorDataPoint(DateTime.MinValue, value);
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(T input)
{
return _value;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
base.Reset();
// re-initialize the current value, constant should ALWAYS return this value
Current = new IndicatorDataPoint(DateTime.MinValue, _value);
}
}
}
+108
View File
@@ -0,0 +1,108 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
namespace QuantConnect.Indicators
{
/// <summary>
/// A momentum indicator developed by Edwin “Sedge” Coppock in October 1965.
/// The goal of this indicator is to identify long-term buying opportunities in the S&amp;P500 and Dow Industrials.
/// Source: http://stockcharts.com/school/doku.php?id=chart_school:technical_indicators:coppock_curve
/// </summary>
public class CoppockCurve : IndicatorBase<IndicatorDataPoint>, IIndicatorWarmUpPeriodProvider
{
private readonly RateOfChangePercent _longRoc;
private readonly LinearWeightedMovingAverage _lwma;
private readonly RateOfChangePercent _shortRoc;
/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _lwma.IsReady;
/// <summary>
/// Required period, in data points, for the indicator to be ready and fully initialized.
/// </summary>
public int WarmUpPeriod { get; }
/// <summary>
/// Initializes a new instance of the <see cref="CoppockCurve" /> indicator with its default values.
/// </summary>
public CoppockCurve()
: this(11, 14, 10)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CoppockCurve"/> indicator
/// </summary>
/// <param name="shortRocPeriod">The period for the short ROC</param>
/// <param name="longRocPeriod">The period for the long ROC</param>
/// <param name="lwmaPeriod">The period for the LWMA</param>
public CoppockCurve(int shortRocPeriod, int longRocPeriod, int lwmaPeriod)
: this($"CC({shortRocPeriod},{longRocPeriod},{lwmaPeriod})", shortRocPeriod, longRocPeriod, lwmaPeriod)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CoppockCurve" /> indicator
/// </summary>
/// <param name="name">A name for the indicator</param>
/// <param name="shortRocPeriod">The period for the short ROC</param>
/// <param name="longRocPeriod">The period for the long ROC</param>
/// <param name="lwmaPeriod">The period for the LWMA</param>
public CoppockCurve(string name, int shortRocPeriod, int longRocPeriod, int lwmaPeriod)
: base(name)
{
_shortRoc = new RateOfChangePercent(shortRocPeriod);
_longRoc = new RateOfChangePercent(longRocPeriod);
_lwma = new LinearWeightedMovingAverage(lwmaPeriod);
// Define our warmup
// LWMA does not get updated until ROC are warmed up and ready, so add our periods.
// Then minus 1 because on the same point ROC is ready LWMA will receive its first point.
WarmUpPeriod = Math.Max(_shortRoc.WarmUpPeriod, _longRoc.WarmUpPeriod) + lwmaPeriod - 1;
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
base.Reset();
_shortRoc.Reset();
_longRoc.Reset();
_lwma.Reset();
}
/// <summary>
/// Computes the next value of this indicator from the given state
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>A new value for this indicator</returns>
protected override decimal ComputeNextValue(IndicatorDataPoint input)
{
_shortRoc.Update(input);
_longRoc.Update(input);
if (!_longRoc.IsReady || !_shortRoc.IsReady)
{
return decimal.Zero;
}
_lwma.Update(input.EndTime, _shortRoc.Current.Value + _longRoc.Current.Value);
return _lwma.Current.Value;
}
}
}
+108
View File
@@ -0,0 +1,108 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using QuantConnect.Data.Market;
namespace QuantConnect.Indicators
{
/// <summary>
/// The Correlation Indicator is a valuable tool in technical analysis, designed to quantify the degree of
/// relationship between the price movements of a target security (e.g., a stock or ETF) and a reference
/// market index. It measures how closely the targets price changes are aligned with the fluctuations of
/// the index over a specific period of time, providing insights into the targets susceptibility to market
/// movements.
/// A positive correlation indicates that the target tends to move in the same direction as the market index,
/// while a negative correlation suggests an inverse relationship. A correlation close to 0 implies a weak or
/// no linear relationship.
/// Commonly, the SPX index is employed as the benchmark for the overall market when calculating correlation,
/// ensuring a consistent and reliable reference point. This helps traders and investors make informed decisions
/// regarding the risk and behavior of the target security in relation to market trends.
///
/// The indicator only updates when both assets have a price for a time step. When a bar is missing for one of the assets,
/// the indicator value fills forward to improve the accuracy of the indicator.
/// </summary>
public class Correlation : DualSymbolIndicator<IBaseDataBar>
{
/// <summary>
/// Correlation type
/// </summary>
private readonly CorrelationType _correlationType;
/// <summary>
/// Gets a flag indicating when the indicator is ready and fully initialized
/// </summary>
public override bool IsReady => TargetDataPoints.IsReady && ReferenceDataPoints.IsReady;
/// <summary>
/// Creates a new Correlation indicator with the specified name, target, reference,
/// and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="correlationType">Correlation type</param>
public Correlation(string name, Symbol targetSymbol, Symbol referenceSymbol, int period, CorrelationType correlationType = CorrelationType.Pearson)
: base(name, targetSymbol, referenceSymbol, period)
{
// Assert the period is greater than two, otherwise the correlation can not be computed
if (period < 2)
{
throw new ArgumentException($"Period parameter for Correlation indicator must be greater than 2 but was {period}");
}
_correlationType = correlationType;
}
/// <summary>
/// Creates a new Correlation indicator with the specified target, reference,
/// and period values
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <param name="correlationType">Correlation type</param>
public Correlation(Symbol targetSymbol, Symbol referenceSymbol, int period, CorrelationType correlationType = CorrelationType.Pearson)
: this($"Correlation({period})", targetSymbol, referenceSymbol, period, correlationType)
{
}
/// <summary>
/// Computes the correlation value usuing symbols values
/// correlation values assing into _correlation property
/// </summary>
protected override decimal ComputeIndicator()
{
var targetDataPoints = TargetDataPoints.Select(x => (double)x.Close);
var referenceDataPoints = ReferenceDataPoints.Select(x => (double)x.Close);
var newCorrelation = 0d;
if (_correlationType == CorrelationType.Pearson)
{
newCorrelation = MathNet.Numerics.Statistics.Correlation.Pearson(targetDataPoints, referenceDataPoints);
}
if (_correlationType == CorrelationType.Spearman)
{
newCorrelation = MathNet.Numerics.Statistics.Correlation.Spearman(targetDataPoints, referenceDataPoints);
}
if (newCorrelation.IsNaNOrZero())
{
newCorrelation = 0;
}
return Extensions.SafeDecimalCast(newCorrelation);
}
}
}
+45
View File
@@ -0,0 +1,45 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace QuantConnect.Indicators
{
/// <summary>
/// Defines the different types of Correlation
/// </summary>
public enum CorrelationType
{
/// <summary>
/// Pearson Correlation (Product-Moment Correlation):
/// Measures the linear relationship between two datasets. The coefficient ranges from -1 to 1.
/// A value of 1 indicates a perfect positive linear relationship, -1 indicates a perfect
/// negative linear relationship, and 0 indicates no linear relationship.
/// It assumes that both datasets are normally distributed and the relationship is linear.
/// It is sensitive to outliers which can affect the correlation significantly.
/// </summary>
Pearson,
/// <summary>
/// Spearman Correlation (Rank Correlation):
/// Measures the strength and direction of the monotonic relationship between two datasets.
/// Instead of calculating the coefficient using raw data, it uses the rank of the data points.
/// This method is non-parametric and does not assume a normal distribution of the datasets.
/// It's useful when the data is not normally distributed or when the relationship is not linear.
/// Spearman's correlation is less sensitive to outliers than Pearson's correlation.
/// The coefficient also ranges from -1 to 1 with similar interpretations for the values,
/// but it reflects monotonic relationships rather than only linear ones.
/// </summary>
Spearman
}
}
+134
View File
@@ -0,0 +1,134 @@
/*
* QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals.
* Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System;
using QuantConnect.Data.Market;
using MathNet.Numerics.Statistics;
namespace QuantConnect.Indicators
{
/// <summary>
/// This indicator computes the Covariance of two assets using the given Look-Back period.
/// The Covariance of two assets is a measure of their co-movement.
/// </summary>
public class Covariance : DualSymbolIndicator<IBaseDataBar>
{
/// <summary>
/// RollingWindow of returns of the target symbol in the given period
/// </summary>
private readonly RollingWindow<double> _targetReturns;
/// <summary>
/// RollingWindow of returns of the reference symbol in the given period
/// </summary>
private readonly RollingWindow<double> _referenceReturns;
/// <summary>
/// Gets a flag indicating when the indicator is ready and fully initialized
/// </summary>
public override bool IsReady => _targetReturns.IsReady && _referenceReturns.IsReady;
/// <summary>
/// Creates a new Covariance indicator with the specified name, target, reference,
/// and period values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
public Covariance(string name, Symbol targetSymbol, Symbol referenceSymbol, int period)
: base(name, targetSymbol, referenceSymbol, 2)
{
// Assert the period is greater than two, otherwise the covariance can not be computed
if (period < 2)
{
throw new ArgumentException($"Period parameter for Covariance indicator must be greater than 2 but was {period}.");
}
_targetReturns = new RollingWindow<double>(period);
_referenceReturns = new RollingWindow<double>(period);
WarmUpPeriod += (period - 2) + 1;
}
/// <summary>
/// Creates a new Covariance indicator with the specified target, reference,
/// and period values
/// </summary>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
public Covariance(Symbol targetSymbol, Symbol referenceSymbol, int period)
: this($"COV({period})", targetSymbol, referenceSymbol, period)
{
}
/// <summary>
/// Creates a new Covariance indicator with the specified name, period, target and
/// reference values
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="period">The period of this indicator</param>
/// <param name="targetSymbol">The target symbol of this indicator</param>
/// <param name="referenceSymbol">The reference symbol of this indicator</param>
/// <remarks>Constructor overload for backward compatibility.</remarks>
public Covariance(string name, int period, Symbol targetSymbol, Symbol referenceSymbol)
: this(name, targetSymbol, referenceSymbol, period)
{
}
/// <summary>
/// Computes the returns with the new given data point and the last given data point
/// </summary>
/// <param name="rollingWindow">The collection of data points from which we want
/// to compute the return</param>
/// <returns>The returns with the new given data point</returns>
private static double GetNewReturn(IReadOnlyWindow<IBaseDataBar> rollingWindow)
{
return (double)(rollingWindow[0].Close.SafeDivision(rollingWindow[1].Close) - 1);
}
/// <summary>
/// Computes the covariance value of the target in relation with the reference
/// using the target and reference returns
/// </summary>
protected override decimal ComputeIndicator()
{
if (TargetDataPoints.IsReady)
{
_targetReturns.Add(GetNewReturn(TargetDataPoints));
}
if (ReferenceDataPoints.IsReady)
{
_referenceReturns.Add(GetNewReturn(ReferenceDataPoints));
}
var covarianceComputed = _targetReturns.Covariance(_referenceReturns);
// Avoid division with NaN or by zero
return (decimal)(!covarianceComputed.IsNaNOrZero() ? covarianceComputed : 0);
}
/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
_targetReturns.Reset();
_referenceReturns.Reset();
base.Reset();
}
}
}

Some files were not shown because too many files have changed in this diff Show More