Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Algorithm/QCAlgorithm.Indicators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2013,6 +2013,26 @@ public SchaffTrendCycle STC(Symbol symbol, int cyclePeriod, int fastPeriod, int
return schaffTrendCycle;
}

/// <summary>
/// Creates a new SmoothedForceIndex indicator
/// </summary>
/// <param name="symbol">The symbol for the indicator to track</param>
/// <param name="atrPeriod">The period used to calculate the Average True Range (ATR)</param>
/// <param name="stdDevPeriod">The period used to calculate the Standard Deviation of close prices</param>
/// <param name="stdDevSmoothingPeriod">The period used to smooth the Standard Deviation with a moving average</param>
/// <param name="resolution">The resolution</param>
/// <param name="maType">The type of moving average used to smooth the Standard Deviation</param>
/// <param name="selector">Selects a value from the BaseData to send into the indicator, if null defaults to casting the input value to a TradeBar</param>
[DocumentationAttribute(Indicators)]

public SmoothedForceIndex SFX(Symbol symbol, int atrPeriod, int stdDevPeriod, int stdDevSmoothingPeriod, Resolution? resolution = null, MovingAverageType maType = MovingAverageType.Simple, Func<IBaseData, TradeBar> selector = null)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Volume isn't required for SFX implementation? the base type should be the more generic BarIndicator instead of TradeBarIndicator
maType -> should be expanded to movingAverageType see other similar arguments in this file
2027 empty line should be removed

{
var name = CreateIndicatorName(symbol, $"SFX({atrPeriod},{stdDevPeriod},{stdDevSmoothingPeriod})", resolution);
var smoothedforceindex = new SmoothedForceIndex(name, atrPeriod, stdDevPeriod, stdDevSmoothingPeriod, maType);
InitializeIndicator(smoothedforceindex, resolution, selector, symbol);
return smoothedforceindex;
}

/// <summary>
/// Creates a new SmoothedOnBalanceVolume indicator for the symbol. The indicator will be automatically
/// updated on the given resolution.
Expand Down
108 changes: 108 additions & 0 deletions Indicators/SmoothedForceIndex.cs
Original file line number Diff line number Diff line change
@@ -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
{
/// <summary>
/// The Smoothed Force Index (SFX) is a composite volatility indicator.
/// It combines the Average True Range (ATR), Standard Deviation of close prices,
/// and a moving average of the Standard Deviation to provide a smoother volatility measure.
/// SFX is designed to filter out noise and help detect changes in volatility regimes.
/// </summary>
public class SmoothedForceIndex : TradeBarIndicator, IIndicatorWarmUpPeriodProvider
{
///<summary>
/// Gets the average true range
/// </summary>
public AverageTrueRange AverageTrueRange { get; }

///<summary>
/// Gets the standard deviation
/// </summary>
public StandardDeviation StandardDeviation { get; }

///<summary>
/// Gets the moving average standard deviation
/// </summary>
public IndicatorBase<IndicatorDataPoint> MovingAverageStandardDeviation { get; }

/// <summary>
/// Gets a flag indicating when this indicator is ready and fully initialized
/// </summary>
public override bool IsReady => AverageTrueRange.IsReady && StandardDeviation.IsReady && MovingAverageStandardDeviation.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 Smoothed Force Index (SFX) indicator.
/// </summary>
/// <param name="name">The name of this indicator</param>
/// <param name="atrPeriod">The period used to calculate the Average True Range (ATR)</param>
/// <param name="stdDevPeriod">The period used to calculate the Standard Deviation of close prices</param>
/// <param name="stdDevSmoothingPeriod">The period used to smooth the Standard Deviation with a moving average</param>
/// <param name="maType">The type of moving average used to smooth the Standard Deviation</param>
public SmoothedForceIndex(string name, int atrPeriod, int stdDevPeriod, int stdDevSmoothingPeriod, MovingAverageType maType = MovingAverageType.Simple)
: base(name)
{
AverageTrueRange = new AverageTrueRange(atrPeriod, MovingAverageType.Wilders);
StandardDeviation = new StandardDeviation(stdDevPeriod);
MovingAverageStandardDeviation = maType.AsIndicator($"{name}_{maType}", stdDevSmoothingPeriod).Of(StandardDeviation, waitForFirstToReady: false);

WarmUpPeriod = Math.Max(AverageTrueRange.WarmUpPeriod, Math.Max(StandardDeviation.WarmUpPeriod, stdDevSmoothingPeriod));
}

/// <summary>
/// Creates a new Smoothed Force Index (SFX) indicator with a default name.
/// </summary>
/// <param name="atrPeriod">The period used to calculate the Average True Range (ATR)</param>
/// <param name="stdDevPeriod">The period used to calculate the Standard Deviation of close prices</param>
/// <param name="stdDevSmoothingPeriod">The period used to smooth the Standard Deviation with a moving average</param>
/// <param name="maType">The type of moving average used to smooth the Standard Deviation</param>
public SmoothedForceIndex(int atrPeriod, int stdDevPeriod, int stdDevSmoothingPeriod, MovingAverageType maType = MovingAverageType.Simple)
: this($"SFX({atrPeriod},{stdDevPeriod},{stdDevSmoothingPeriod})", atrPeriod, stdDevPeriod, stdDevSmoothingPeriod, maType)
{
}

/// <summary>
/// Computes the next value of this indicator from the given trade bar input.
/// </summary>
/// <param name="input">The input given to the indicator</param>
/// <returns>The input is returned unmodified.</returns>
protected override decimal ComputeNextValue(TradeBar input)
{
AverageTrueRange.Update(input);
StandardDeviation.Update(new IndicatorDataPoint(input.EndTime, input.Close));

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor but why not just call .Update(input) instead of creating the indicator data point


return input.Value;
}

/// <summary>
/// Resets this indicator to its initial state
/// </summary>
public override void Reset()
{
AverageTrueRange.Reset();
StandardDeviation.Reset();
MovingAverageStandardDeviation.Reset();
base.Reset();
}
}
}
77 changes: 77 additions & 0 deletions Tests/Indicators/SmoothedForceIndexTests.cs
Comment thread
SaiRevanth25 marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* 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 NUnit.Framework;
using QuantConnect.Data.Market;
using QuantConnect.Indicators;

namespace QuantConnect.Tests.Indicators
{
[TestFixture]
public class SmoothedForceIndexTests : CommonIndicatorTests<TradeBar>
Comment thread
SaiRevanth25 marked this conversation as resolved.
{
protected override IndicatorBase<TradeBar> CreateIndicator()
{
RenkoBarSize = 1m;
// VolumeRenkoBarSize = 0.5m; // when uncommented test AcceptsVolumeRenkoBarsAsInput in hanging
return new SmoothedForceIndex(12, 12, 3);
}

protected override string TestFileName => "spy_with_SmoothedForceIndex.csv";

protected override string TestColumnName => "atr";

protected override Action<IndicatorBase<TradeBar>, double> Assertion =>
(indicator, expected) =>
Assert.AreEqual(expected, (double) ((SmoothedForceIndex) indicator).AverageTrueRange.Current.Value, 1e-3);

[Test]
public void CompareWithExternalDataAverageTrueRange()
{
TestHelper.TestIndicator(
CreateIndicator() as SmoothedForceIndex,
TestFileName,
"atr",
(ind, expected) => Assert.AreEqual(expected,
(double)((SmoothedForceIndex)ind).AverageTrueRange.Current.Value, 1e-3)
);
}

[Test]
public void CompareWithExternalStandardDeviation()
{
TestHelper.TestIndicator(
CreateIndicator() as SmoothedForceIndex,
TestFileName,
"std_dev",
(ind, expected) => Assert.AreEqual(expected,
(double)((SmoothedForceIndex)ind).StandardDeviation.Current.Value, 1e-3)
);
}

[Test]
public void CompareWithExternalMovingAverageStandardDeviation()
{
TestHelper.TestIndicator(
CreateIndicator() as SmoothedForceIndex,
TestFileName,
"ma_std_dev",
(ind, expected) => Assert.AreEqual(expected,
(double)((SmoothedForceIndex)ind).MovingAverageStandardDeviation.Current.Value, 1e-3)
);
}
}
}
3 changes: 3 additions & 0 deletions Tests/QuantConnect.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,9 @@
<None Update="TestData\spy_with_ForceIndex.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\spy_with_SmoothedForceIndex.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="TestData\spy_with_hilbert.csv">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
Expand Down
Loading