Skip to content

Commit

Permalink
Implement Average Range (AR) Indicator (#8404)
Browse files Browse the repository at this point in the history
* Add Average Daily Range indicator and tests

- Implemented AverageDailyRange indicator
- The indicator uses a Simple Moving Average (SMA)
- Created unit tests for the indicator
- Includes example input data and test file (spy_adr.csv)

* Refactor AverageDailyRange Indicator

- Renamed AverageDailyRange to AverageRage for a more generic approach
- Replaced explicit types with 'var'
- Updated method name in test cases
- Placed AR method in the correct alphabetical order

* Solving minor issues with AR indicator

- Replace TradeBar with IBaseDataBar
- Remove unnecessary override methods
  • Loading branch information
JosueNina authored Nov 15, 2024
1 parent 7bbf42f commit 725ad73
Show file tree
Hide file tree
Showing 5 changed files with 708 additions and 0 deletions.
18 changes: 18 additions & 0 deletions Algorithm/QCAlgorithm.Indicators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,23 @@ public Alpha A(Symbol target, Symbol reference, int alphaPeriod = 1, int betaPer
return alpha;
}

/// <summary>
/// Creates a new Average Range (AR) indicator.
/// </summary>
/// <param name="symbol">The symbol whose Average Range we want to calculate</param>
/// <param name="period">The period over which to compute the Average Range</param>
/// <param name="resolution">The resolution</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator. If null, defaults to the Value property of BaseData (x => x.Value).</param>
/// <returns>The Average Range indicator for the requested symbol over the specified period</returns>
[DocumentationAttribute(Indicators)]
public AverageRange AR(Symbol symbol, int period, Resolution? resolution = null, Func<IBaseData, IBaseDataBar> selector = null)
{
var name = CreateIndicatorName(symbol, $"AR({period})", resolution);
var averageRange = new AverageRange(name, period);
InitializeIndicator(averageRange, resolution, selector, symbol);
return averageRange;
}

/// <summary>
/// Creates a new ARIMA indicator.
/// </summary>
Expand Down Expand Up @@ -1894,6 +1911,7 @@ public SimpleMovingAverage SMA(Symbol symbol, int period, Resolution? resolution
return simpleMovingAverage;
}


/// <summary>
/// Creates a new Schaff Trend Cycle indicator
/// </summary>
Expand Down
81 changes: 81 additions & 0 deletions Indicators/AverageRange.cs
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
80 changes: 80 additions & 0 deletions Tests/Indicators/AverageRangeTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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 NUnit.Framework;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;

namespace QuantConnect.Tests.Indicators
{
[TestFixture]
public class AverageRangeTests : CommonIndicatorTests<IBaseDataBar>
{
protected override IndicatorBase<IBaseDataBar> CreateIndicator()
{
RenkoBarSize = 1m;
VolumeRenkoBarSize = 0.5m;
return new AverageRange(20);
}
protected override string TestFileName => "spy_adr.csv";

protected override string TestColumnName => "adr";

[Test]
public void ComputesCorrectly()
{
var period = 20;
var adr = new AverageRange(period);
var values = new List<TradeBar>();
for (int i = 0; i < period; i++)
{
var value = new TradeBar
{
Symbol = Symbol.Empty,
Time = DateTime.Now.AddSeconds(i),
High = 2 * i,
Low = i
};
adr.Update(value);
values.Add(value);
}
var expected = values.Average(x => x.High - x.Low);
Assert.AreEqual(expected, adr.Current.Value);
}

[Test]
public void IsReadyAfterPeriodUpdates()
{
var period = 5;
var adr = new AverageRange(period);
for (int i = 0; i < period; i++)
{
Assert.IsFalse(adr.IsReady);
var value = new TradeBar
{
Symbol = Symbol.Empty,
Time = DateTime.Now.AddSeconds(i),
High = 2 * i,
Low = i
};
adr.Update(value);
}
Assert.IsTrue(adr.IsReady);
}
}
}
3 changes: 3 additions & 0 deletions Tests/QuantConnect.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,9 @@
<Content Include="TestData\spy_with_vtx.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
<Content Include="TestData\spy_adr.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Include="TestData\symbol-properties\symbol-properties-database.csv">
Expand Down
Loading

0 comments on commit 725ad73

Please sign in to comment.