Files
Miha Kralj 6f0a339c9b fix: resolve build and test errors
- Sar.Quantower.Tests.cs: add missing opening quote on string literal (line 48)
- Exports.cs: rename Correlation.Batch → Correl.Batch (CS0103)
- Ad.Validation.Tests.cs: fix Ooples OutputValues key "Ad" → "Adl"
2026-03-16 12:45:13 -07:00

76 lines
2.5 KiB
C#
Raw Permalink 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>
/// Kc: Keltner Channel - Quantower Indicator Adapter
/// A volatility-based envelope using EMA as the middle line and ATR for band width.
/// Middle = EMA(close, period) with warmup compensation
/// Upper = Middle + (multiplier × ATR)
/// Lower = Middle - (multiplier × ATR)
/// ATR uses RMA (Wilder's smoothing) with warmup compensation.
/// </summary>
public sealed class KcIndicator : 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 Kc? _indicator;
public int MinHistoryDepths => Period * 2;
public override string ShortName => $"Kc({Period},{Multiplier})";
public KcIndicator()
{
Name = "Kc - Keltner Channel";
Description = "EMA-based channel with ATR-derived band width";
SeparateWindow = false;
OnBackGround = true;
}
protected override void OnInit()
{
_indicator = new Kc(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);
}
}