Files
QuanTAlib/lib/channels/starchannel/Starchannel.Quantower.cs
T
Miha Kralj fdfbfd98f0 Add Starchannel indicator implementation and validation tests
- Implemented the Starchannel class, which calculates a volatility-based envelope using SMA as the middle line and ATR for band width.
- Added methods for updating the indicator with new data, batch calculations, and state management.
- Created comprehensive unit tests for the Starchannel indicator, validating various scenarios including manual calculations, consistency across modes, eventing, and handling of large datasets.
- Ensured that the indicator's outputs are finite and that band widths are consistent across different calculation modes.
2026-01-21 17:21:29 -05:00

74 lines
2.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Drawing;
using TradingPlatform.BusinessLayer;
using static QuanTAlib.IndicatorExtensions;
namespace QuanTAlib;
/// <summary>
/// Starchannel: Stoller Average Range Channel - Quantower Indicator Adapter
/// A volatility-based envelope using SMA as the middle line and ATR for band width.
/// Middle = SMA(close, period)
/// Upper = Middle + (multiplier × ATR)
/// Lower = Middle - (multiplier × ATR)
/// ATR uses RMA (Wilder's smoothing) with warmup compensation.
/// </summary>
public sealed class StarchannelIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Period", sortIndex: 10, minimum: 1, maximum: 500, increment: 1, decimalPlaces: 0)]
public int Period { get; set; } = 20;
[InputParameter("Multiplier", sortIndex: 20, minimum: 0.1, maximum: 10.0, increment: 0.1, decimalPlaces: 1)]
public double Multiplier { get; set; } = 2.0;
[InputParameter("Show Cold Values", sortIndex: 100)]
public bool ShowColdValues { get; set; } = true;
private Starchannel? _indicator;
public int MinHistoryDepths => Period;
public override string ShortName => $"Starchannel({Period},{Multiplier})";
public StarchannelIndicator()
{
Name = "Starchannel - Stoller Average Range Channel";
Description = "SMA-based channel with ATR-derived band width";
SeparateWindow = false;
OnBackGround = true;
}
protected override void OnInit()
{
_indicator = new Starchannel(Period, Multiplier);
AddLineSeries(new LineSeries("Middle", Color.DodgerBlue, 2, LineStyle.Solid));
AddLineSeries(new LineSeries("Upper", Color.FromArgb(255, 180, 180), 1, LineStyle.Dash));
AddLineSeries(new LineSeries("Lower", Color.FromArgb(180, 180, 255), 1, LineStyle.Dash));
}
protected override void OnUpdate(UpdateArgs args)
{
if (_indicator is null)
return;
var item = HistoricalData[0, SeekOriginHistory.End];
bool isNew = args.IsNewBar();
TBar input = new(
time: item.TimeLeft,
open: item[PriceType.Open],
high: item[PriceType.High],
low: item[PriceType.Low],
close: item[PriceType.Close],
volume: item[PriceType.Volume]
);
_indicator.Update(input, isNew);
bool isHot = _indicator.IsHot;
LinesSeries[0].SetValue(_indicator.Last.Value, isHot, ShowColdValues);
LinesSeries[1].SetValue(_indicator.Upper.Value, isHot, ShowColdValues);
LinesSeries[2].SetValue(_indicator.Lower.Value, isHot, ShowColdValues);
}
}