### Compose Built-in Indicators in C# Source: https://context7.com/quantower/scripts/llms.txt Demonstrates how to access and compose multiple built-in indicators (SMA, EMA, ATR, RSI) within a custom indicator in C#. It shows how to attach, retrieve values from, and clean up these composed indicators. ```csharp using TradingPlatform.BusinessLayer; using System.Drawing; namespace CustomIndicators; public class CompositeIndicator : Indicator { private Indicator sma; private Indicator ema; private Indicator atr; private Indicator rsi; public CompositeIndicator() { this.Name = "Composite Indicator"; this.AddLineSeries("Signal", Color.Blue, 2, LineStyle.Solid); this.SeparateWindow = false; } protected override void OnInit() { // Access built-in indicators this.sma = Core.Indicators.BuiltIn.SMA(20, PriceType.Close); this.ema = Core.Indicators.BuiltIn.EMA(9, PriceType.Close); this.atr = Core.Indicators.BuiltIn.ATR(14, MaMode.SMA); this.rsi = Core.Indicators.BuiltIn.RSI(14, PriceType.Close, RSIMode.Exponential); // Attach indicators to current data this.AddIndicator(this.sma); this.AddIndicator(this.ema); this.AddIndicator(this.atr); this.AddIndicator(this.rsi); } protected override void OnUpdate(UpdateArgs args) { if (this.Count < 20) return; // Get values from composed indicators double smaValue = this.sma.GetValue(); double emaValue = this.ema.GetValue(); double atrValue = this.atr.GetValue(); double rsiValue = this.rsi.GetValue(); // Custom logic using multiple indicators if (emaValue > smaValue && rsiValue < 70) { this.SetValue(this.Close() + atrValue); this.LinesSeries[0].SetMarker(0, Color.Green); } else if (emaValue < smaValue && rsiValue > 30) { this.SetValue(this.Close() - atrValue); this.LinesSeries[0].SetMarker(0, Color.Red); } } protected override void OnClear() { // Clean up composed indicators this.RemoveIndicator(this.sma); this.RemoveIndicator(this.ema); this.RemoveIndicator(this.atr); this.RemoveIndicator(this.rsi); this.sma?.Dispose(); this.ema?.Dispose(); this.atr?.Dispose(); this.rsi?.Dispose(); } } ``` -------------------------------- ### Chain Custom Historical Data with Indicators in C# Source: https://context7.com/quantower/scripts/llms.txt Illustrates using `HistoricalDataCustom` in C# to feed calculated values into other indicators, enabling complex multi-step calculations. It shows how to create custom data, attach a smoothing indicator (SMA), and update both the raw and smoothed values. ```csharp using TradingPlatform.BusinessLayer; using System.Drawing; namespace CustomIndicators; public class ChainedIndicator : Indicator { private HistoricalDataCustom customData; private Indicator smoothingMA; [InputParameter("Source period", 0, 1, 100)] public int SourcePeriod = 14; [InputParameter("Smoothing period", 1, 1, 50)] public int SmoothPeriod = 5; public ChainedIndicator() { this.Name = "Chained Calculation"; this.AddLineSeries("Raw", Color.Gray, 1, LineStyle.Solid); this.AddLineSeries("Smoothed", Color.Blue, 2, LineStyle.Solid); this.SeparateWindow = true; } protected override void OnInit() { // Create custom historical data synchronized with this indicator this.customData = new HistoricalDataCustom(this); // Create MA that will smooth our custom calculated values this.smoothingMA = Core.Indicators.BuiltIn.SMA(this.SmoothPeriod, PriceType.Close); // Attach MA to custom data (it will calculate on custom values) this.customData.AddIndicator(this.smoothingMA); } protected override void OnUpdate(UpdateArgs args) { if (this.Count < this.SourcePeriod) return; // Calculate a custom value (example: price momentum) double currentPrice = this.GetPrice(PriceType.Close); double pastPrice = this.GetPrice(PriceType.Close, this.SourcePeriod); double momentum = ((currentPrice - pastPrice) / pastPrice) * 100; // Set raw value this.SetValue(momentum, 0); // Feed calculated value to custom historical data // The MA indicator attached to customData will smooth these values this.customData.SetValue(0d, 0d, 0d, momentum); // Get smoothed value from the MA indicator if (this.Count >= this.SourcePeriod + this.SmoothPeriod) { double smoothedValue = this.smoothingMA.GetValue(); this.SetValue(smoothedValue, 1); } } } ``` -------------------------------- ### Implement Simple Moving Average (SMA) in C# Source: https://context7.com/quantower/scripts/llms.txt Calculates the arithmetic mean of prices over a specified period. It uses the Indicator base class and supports configurable periods and various price source types. ```csharp using TradingPlatform.BusinessLayer; using System.Drawing; namespace MovingAverages; public sealed class IndicatorSimpleMovingAverage : Indicator, IWatchlistIndicator { [InputParameter("Period of Simple Moving Average", 0, 1, 9999, 1, 1)] public int Period = 20; [InputParameter("Sources prices for MA", 1, variants: new object[]{ "Close", PriceType.Close, "Open", PriceType.Open, "High", PriceType.High, "Low", PriceType.Low, "Typical", PriceType.Typical, "Median", PriceType.Median, "Weighted", PriceType.Weighted })] public PriceType SourcePrice = PriceType.Close; public int MinHistoryDepths => this.Period; public override string ShortName => $"SMA ({this.Period}:{this.SourcePrice})"; public IndicatorSimpleMovingAverage() : base() { this.Name = "Simple Moving Average"; this.Description = "Average price for the last N periods"; this.AddLineSeries("SMA", Color.Red, 1, LineStyle.Solid); this.SeparateWindow = false; } protected override void OnUpdate(UpdateArgs args) { if (this.Count < this.MinHistoryDepths) return; double sum = 0.0; for (int i = 0; i < this.Period; i++) sum += this.GetPrice(this.SourcePrice, i); this.SetValue(sum / this.Period); } } ``` -------------------------------- ### Implement Bollinger Bands Indicator in C# Source: https://context7.com/quantower/scripts/llms.txt This C# code implements the Bollinger Bands indicator for the Quantower trading platform. It calculates and plots upper, middle, and lower bands based on a moving average and standard deviation. Dependencies include the TradingPlatform.BusinessLayer namespace. Inputs are period, confidence interval, source prices, and moving average type. ```csharp using System; using System.Drawing; using TradingPlatform.BusinessLayer; namespace Channels; public sealed class IndicatorBollingerBands : Indicator, IWatchlistIndicator { [InputParameter("Period of MA for envelopes", 0, 1, 999)] public int Period = 20; [InputParameter("Value of confidence interval", 1, 0.01, 100.0, 0.01, 2)] public double D = 2.0; [InputParameter("Sources prices for MA", 2, variants: new object[] { "Close", PriceType.Close, "Open", PriceType.Open, "High", PriceType.High, "Low", PriceType.Low })] public PriceType SourcePrices = PriceType.Close; [InputParameter("Type of moving average", 3, variants: new object[]{ "Simple Moving Average", MaMode.SMA, "Exponential Moving Average", MaMode.EMA, "Smoothed Moving Average", MaMode.SMMA, "Linearly Weighted Moving Average", MaMode.LWMA, })] public MaMode MaType = MaMode.SMA; private Indicator ma; public int MinHistoryDepths => this.Period; public override string ShortName => $"BB ({this.Period}:{this.D})"; public IndicatorBollingerBands() : base() { this.Name = "Bollinger Bands"; this.Description = "Provides a relative definition of high and low based on standard deviation"; // Define three lines: Upper, Middle, Lower bands this.AddLineSeries("Upper Band", Color.Red, 2, LineStyle.Solid); this.AddLineSeries("Middle Band", Color.Gray, 2, LineStyle.Solid); this.AddLineSeries("Lower Band", Color.Green, 2, LineStyle.Solid); this.SeparateWindow = false; } protected override void OnInit() { // Use built-in MA indicator this.ma = Core.Indicators.BuiltIn.MA(this.Period, this.SourcePrices, this.MaType); this.AddIndicator(this.ma); } protected override void OnUpdate(UpdateArgs args) { if (this.Count < this.MinHistoryDepths) return; double maValue = this.ma.GetValue(); // Calculate standard deviation double sum = 0.0; for (int i = 0; i < this.Period; i++) sum += Math.Pow(this.GetPrice(this.SourcePrices, i) - maValue, 2); double deviation = this.D * Math.Sqrt(sum / this.Period); // Set Upper, Middle, Lower band values this.SetValue(maValue + deviation, 0); // Upper Band this.SetValue(maValue, 1); // Middle Band this.SetValue(maValue - deviation, 2); // Lower Band } } ``` -------------------------------- ### Pivot Point Indicator Implementation in C# Source: https://context7.com/quantower/scripts/llms.txt This C# code implements the Pivot Point indicator for the Quantower trading platform. It allows users to select different calculation methods (Classic, Camarilla, Fibonacci, Woodie, DeMark) and base periods (Hour, Day, Week, Month). The indicator calculates and displays pivot points, resistance levels (R1, R2, R3), and support levels (S1, S2, S3) on the chart. ```csharp using System; using System.Drawing; using TradingPlatform.BusinessLayer; namespace TrendIndicators; public class IndicatorPivotPoint : Indicator, IWatchlistIndicator { [InputParameter("Base period", 5, variants: new object[] { "Hour", BasePeriod.Hour, "Day", BasePeriod.Day, "Week", BasePeriod.Week, "Month", BasePeriod.Month })] public BasePeriod BasePeriod = BasePeriod.Day; [InputParameter("Range", 10)] public int PeriodValue = 1; [InputParameter("Calculation method", 20, variants: new object[] { "Classic", CalculationMethod.Classic, "Camarilla", CalculationMethod.Camarilla, "Fibonacci", CalculationMethod.Fibonacci, "Woodie", CalculationMethod.Woodie, "DeMark", CalculationMethod.DeMark })] public CalculationMethod IndicatorCalculationMethod = CalculationMethod.Classic; public int MinHistoryDepths => 1; public override string ShortName => $"PP ({this.BasePeriod}: {this.IndicatorCalculationMethod})"; public IndicatorPivotPoint() { this.Name = "Pivot Point"; // Pivot point and resistance/support levels this.AddLineSeries("PP", Color.Gray, 1, LineStyle.Solid); this.AddLineSeries("R1", Color.Red, 1, LineStyle.Solid); this.AddLineSeries("R2", Color.Red, 1, LineStyle.Solid); this.AddLineSeries("R3", Color.Red, 1, LineStyle.Solid); this.AddLineSeries("S1", Color.DodgerBlue, 1, LineStyle.Solid); this.AddLineSeries("S2", Color.DodgerBlue, 1, LineStyle.Solid); this.AddLineSeries("S3", Color.DodgerBlue, 1, LineStyle.Solid); this.SeparateWindow = false; } // Classic Pivot Point calculation example private void CalculateClassicPivot(double high, double low, double close) { double pp = (high + low + close) / 3; double range = high - low; double r1 = 2 * pp - low; double r2 = pp + range; double r3 = r2 + range; double s1 = 2 * pp - high; double s2 = pp - range; double s3 = s2 - range; // Set values to respective line series this.SetValue(pp, 0); // PP this.SetValue(r1, 1); // R1 this.SetValue(r2, 2); // R2 this.SetValue(r3, 3); // R3 this.SetValue(s1, 4); // S1 this.SetValue(s2, 5); // S2 this.SetValue(s3, 6); // S3 } // Fibonacci Pivot calculation private void CalculateFibonacciPivot(double high, double low, double close) { double pp = (high + low + close) / 3; double range = high - low; double r1 = pp + 0.382 * range; double r2 = pp + 0.618 * range; double r3 = pp + range; double s1 = pp - 0.382 * range; double s2 = pp - 0.618 * range; double s3 = pp - range; } } public enum CalculationMethod { Classic, Camarilla, Fibonacci, Woodie, DeMark } ``` -------------------------------- ### Implement Volume Indicator in C# for Quantower Source: https://context7.com/quantower/scripts/llms.txt This C# class implements a custom indicator for the Quantower platform. It calculates volume data and applies visual coloring schemes based on user-defined parameters like bar direction or moving average comparison. ```csharp using System; using System.Drawing; using TradingPlatform.BusinessLayer; namespace BarsDataIndicators; public sealed class IndicatorVolume : Indicator, IWatchlistIndicator { [InputParameter("Volume asset", 10, variants: new object[] { "Base asset", PriceType.Volume, "Quote asset", PriceType.QuoteAssetVolume })] public PriceType VolumeAsset = PriceType.Volume; [InputParameter("MA period", 20, 1, int.MaxValue, 1, 0)] public int SmoothMaPeriod = 21; [InputParameter("Volume coloring scheme", 40, variants: new object[]{ "By bar", VolumeColoringScheme.ByBar, "By difference", VolumeColoringScheme.ByDifference, "Fixed", VolumeColoringScheme.Fixed, "Above/below MA", VolumeColoringScheme.AboveBelowMA, })] public VolumeColoringScheme ColoringScheme = VolumeColoringScheme.ByDifference; private PairColor pairColor; private Indicator sma; public int MinHistoryDepths => Math.Max(this.SmoothMaPeriod, 2); public IndicatorVolume() : base() { this.Name = "Volume"; this.Description = "Volume confirms trend strength or suggests weakness"; this.AddLineSeries("Volume", Color.Gray, 2, LineStyle.Histogramm); this.AddLineSeries("Smooth volume", Color.Orange, 2, LineStyle.Solid); this.SeparateWindow = true; this.pairColor = new PairColor() { Color1 = Color.FromArgb(255, 251, 87, 87), Color2 = Color.FromArgb(255, 0, 178, 89), }; } protected override void OnInit() { this.sma = Core.Indicators.BuiltIn.SMA(this.SmoothMaPeriod, this.VolumeAsset); this.AddIndicator(this.sma); } protected override void OnUpdate(UpdateArgs args) { if (this.Count < 2) return; double volume = this.VolumeAsset == PriceType.Volume ? this.Volume() : this.QuoteAssetVolume(); double curVolume = (double.IsNaN(volume) || volume == 0) ? this.Ticks() : volume; double prevVolume = this.Count > 1 ? this.GetValue(1) : curVolume; this.SetValue(curVolume); switch (this.ColoringScheme) { case VolumeColoringScheme.ByBar: this.LinesSeries[0].SetMarker(0, this.Open() < this.Close() ? pairColor.Color2 : pairColor.Color1); break; case VolumeColoringScheme.ByDifference: this.LinesSeries[0].SetMarker(0, prevVolume < curVolume ? pairColor.Color2 : pairColor.Color1); break; } if (this.Count >= this.SmoothMaPeriod) { double smaValue = this.sma.GetValue(); this.SetValue(smaValue, 1); if (this.ColoringScheme == VolumeColoringScheme.AboveBelowMA) this.LinesSeries[0].SetMarker(0, smaValue < curVolume ? pairColor.Color2 : pairColor.Color1); } } public enum VolumeColoringScheme { ByBar, ByDifference, Fixed, AboveBelowMA } } ``` -------------------------------- ### SuperTrend Indicator Implementation in C# Source: https://context7.com/quantower/scripts/llms.txt This C# code implements the SuperTrend indicator, which identifies trend direction and support/resistance levels using the Average True Range (ATR). It includes configurable parameters for ATR period, digit multiplier, and trend colors. The indicator calculates SuperTrend bands and adjusts them based on trend continuity, then sets the indicator value and color according to the current trend. ```csharp using System.Drawing; using TradingPlatform.BusinessLayer; namespace TrendIndicators; public class IndicatorSuperTrend : Indicator, IWatchlistIndicator { [InputParameter("ATR period", 0, 1, 999, 1, 0)] public int AtrPeriod = 10; [InputParameter("Digit", 1, 0.01, 10, 0.01, 2)] public double Digit = 3; [InputParameter("Up trend color", 3)] public Color UpTrendColor = Color.Green; [InputParameter("Down trend color", 3)] public Color DownTrendColor = Color.Red; private Indicator atrIndicator; private int prevTrend, currTrend; private double prevDown, prevUP, down, up; public int MinHistoryDepths => this.AtrPeriod; public override string ShortName => $"ST ({this.AtrPeriod}: {this.Digit})"; public IndicatorSuperTrend() { this.Name = "SuperTrend"; this.AddLineSeries("ST line", Color.DodgerBlue, 2, LineStyle.Solid); this.SeparateWindow = false; } protected override void OnInit() { this.atrIndicator = Core.Indicators.BuiltIn.ATR(this.AtrPeriod, MaMode.SMA); this.AddIndicator(this.atrIndicator); } protected override void OnUpdate(UpdateArgs args) { if (this.Count < this.AtrPeriod) return; bool isNewBar = args.Reason == UpdateReason.NewBar || args.Reason == UpdateReason.HistoricalBar; if (isNewBar) { this.prevDown = this.up; this.prevTrend = this.currTrend; this.prevUP = this.down; } // Calculate SuperTrend bands using ATR double middle = (this.GetPrice(PriceType.High) + this.GetPrice(PriceType.Low)) / 2; double atr = this.atrIndicator.GetValue(); this.down = middle + (this.Digit * atr); this.up = middle - (this.Digit * atr); // Determine trend direction if (this.GetPrice(PriceType.Close) > this.prevUP) this.currTrend = 1; // Uptrend else if (this.GetPrice(PriceType.Close) < this.prevDown) this.currTrend = -1; // Downtrend else this.currTrend = this.prevTrend; // Adjust bands based on trend continuity if (this.currTrend > 0 && up < this.prevDown && this.currTrend <= this.prevTrend) this.up = this.prevDown; if (this.currTrend < 0 && this.down > this.prevUP && this.currTrend >= this.prevTrend) this.down = this.prevUP; // Set value and color based on trend if (this.currTrend == 1) { this.SetValue(this.up); this.LinesSeries[0].SetMarker(0, this.UpTrendColor); } else { this.SetValue(this.down); this.LinesSeries[0].SetMarker(0, this.DownTrendColor); } } } ``` -------------------------------- ### Implement Ichimoku Cloud Indicator in C# Source: https://context7.com/quantower/scripts/llms.txt This indicator calculates the Tenkan-sen, Kijun-sen, Senkou Spans, and Chinkou Span to identify market trends and support/resistance levels. It utilizes the Quantower BusinessLayer to manage line series, input parameters, and dynamic cloud rendering. ```csharp using System; using System.Drawing; using TradingPlatform.BusinessLayer; namespace Trend; public sealed class IndicatorIchimoku : Indicator, IWatchlistIndicator { private const int TENKAN = 0, KIJUN = 1, SENKOU_SPANA = 2, SENKOU_SPANB = 3, CHINKOU_SPAN = 4; [InputParameter("Tenkan Sen", 0, 1, 9999, 1, 0)] public int TenkanPeriod = 9; [InputParameter("Kijun Sen", 1, 1, 9999, 1, 0)] public int KijunPeriod = 26; [InputParameter("Senkou Span B", 2, 1, 9999, 1, 0)] public int SenkouSpanB = 52; [InputParameter("Cloud up color", 3)] public Color UpColor = Color.FromArgb(50, Color.Green); [InputParameter("Cloud down color", 3)] public Color DownColor = Color.FromArgb(50, Color.Red); private Trend currentTrend; public int MinHistoryDepths => Math.Max(this.TenkanPeriod, Math.Max(this.KijunPeriod, this.SenkouSpanB)); public override string ShortName => $"ICH ({this.TenkanPeriod}: {this.KijunPeriod}: {this.SenkouSpanB})"; public IndicatorIchimoku() : base() { this.Name = "Ichimoku"; this.Description = "Filter low-probability setups from high-probability ones at a glance"; this.AddLineSeries("Tenkan", Color.Blue, 1, LineStyle.Solid); this.AddLineSeries("Kijun", Color.Lime, 1, LineStyle.Solid); this.AddLineSeries("Senkou Span A", Color.SpringGreen, 1, LineStyle.Solid); this.AddLineSeries("Senkou Span B", Color.Red, 1, LineStyle.Solid); this.AddLineSeries("Chinkou Span", Color.FromArgb(255, 153, 0), 1, LineStyle.Solid); this.SeparateWindow = false; } protected override void OnInit() { this.LinesSeries[SENKOU_SPANA].TimeShift = this.KijunPeriod; this.LinesSeries[SENKOU_SPANB].TimeShift = this.KijunPeriod; this.LinesSeries[CHINKOU_SPAN].TimeShift = -this.KijunPeriod; } protected override void OnUpdate(UpdateArgs args) { if (this.Count < this.MinHistoryDepths) return; this.SetValue(GetAverage(this.TenkanPeriod), TENKAN); this.SetValue(GetAverage(this.KijunPeriod), KIJUN); this.SetValue(this.GetPrice(PriceType.Close), CHINKOU_SPAN); double senkouSpanA = (this.GetValue(0, TENKAN) + this.GetValue(0, KIJUN)) / 2; this.SetValue(senkouSpanA, SENKOU_SPANA); double senkouSpanB = GetAverage(this.SenkouSpanB); this.SetValue(senkouSpanB, SENKOU_SPANB); var newTrend = senkouSpanA > senkouSpanB ? Trend.Up : Trend.Down; if (this.currentTrend != newTrend) { this.EndCloud(SENKOU_SPANA, SENKOU_SPANB, GetColorByTrend(this.currentTrend)); this.BeginCloud(SENKOU_SPANA, SENKOU_SPANB, GetColorByTrend(newTrend)); } this.currentTrend = newTrend; } public double GetAverage(int period) { double high = this.GetPrice(PriceType.High); double low = this.GetPrice(PriceType.Low); for (int i = 1; i < period; i++) { high = Math.Max(high, this.GetPrice(PriceType.High, i)); low = Math.Min(low, this.GetPrice(PriceType.Low, i)); } return (high + low) / 2.0; } private Color GetColorByTrend(Trend trend) => trend == Trend.Up ? this.UpColor : this.DownColor; private enum Trend { Unknown, Up, Down } } ``` -------------------------------- ### Implement Exponential Moving Average (EMA) in C# Source: https://context7.com/quantower/scripts/llms.txt Calculates a weighted moving average that prioritizes recent price data. This implementation includes a smoothing coefficient calculation and supports different calculation modes. ```csharp using TradingPlatform.BusinessLayer; using System.Drawing; namespace MovingAverages; public sealed class IndicatorExponentialMovingAverage : Indicator, IWatchlistIndicator { [InputParameter("Period of Exponential Moving Average", 10, 1, 9999, 1, 0)] public int MaPeriod = 9; [InputParameter("Sources prices for MA", 20, variants: new object[] { "Close", PriceType.Close, "Open", PriceType.Open, "High", PriceType.High, "Low", PriceType.Low })] public PriceType SourcePrice = PriceType.Close; [InputParameter("Calculation type", 30, variants: new object[] { "All available data", IndicatorCalculationType.AllAvailableData, "By period", IndicatorCalculationType.ByPeriod, })] public IndicatorCalculationType CalculationType = Indicator.DEFAULT_CALCULATION_TYPE; private double k; public int MinHistoryDepths => this.MaPeriod; public override string ShortName => $"EMA ({this.MaPeriod}: {this.SourcePrice})"; public IndicatorExponentialMovingAverage() : base() { this.Name = "Exponential Moving Average"; this.Description = "The weighted price calculation for the last N periods"; this.AddLineSeries("EMA", Color.DodgerBlue, 1, LineStyle.Solid); this.SeparateWindow = false; } protected override void OnInit() { this.k = 2.0 / (this.MaPeriod + 1); } protected override void OnUpdate(UpdateArgs args) { if (this.Count <= 1) return; double prevEMA = double.IsNaN(this.GetValue(1)) ? this.GetPrice(this.SourcePrice, 1) : this.GetValue(1); double price = this.GetPrice(this.SourcePrice, 0); double ema = prevEMA + this.k * (price - prevEMA); if (this.Count > this.MaPeriod) this.SetValue(ema); } } ``` -------------------------------- ### Implement MACD Indicator in C# Source: https://context7.com/quantower/scripts/llms.txt A custom indicator implementation for Quantower that calculates the MACD line, signal line, and histogram. It utilizes built-in EMA and SMA indicators and requires historical data depth based on the configured periods. ```csharp using System; using System.Drawing; using TradingPlatform.BusinessLayer; namespace Oscillators; public sealed class IndicatorMACD : Indicator, IWatchlistIndicator { [InputParameter("Period of fast EMA", 0, 1, 999, 1, 0)] public int FastPeriod = 12; [InputParameter("Period of slow EMA", 1, 1, 999, 1, 0)] public int SlowPeriod = 26; [InputParameter("Period of signal SMA", 2, 1, 999, 1, 0)] public int SignalPeriod = 9; [InputParameter("Price type", 4, variants: new object[] { "Close", PriceType.Close, "Open", PriceType.Open, "High", PriceType.High, "Low", PriceType.Low })] public PriceType PriceType = PriceType.Close; private Indicator fastEMA; private Indicator slowEMA; private Indicator sma; private HistoricalDataCustom customHD; private int MaxEMAPeriod => Math.Max(this.FastPeriod, this.SlowPeriod); public int MinHistoryDepths => this.MaxEMAPeriod + this.SignalPeriod; public override string ShortName => $"MACD ({this.FastPeriod}: {this.SlowPeriod}: {this.SignalPeriod})"; public IndicatorMACD() : base() { this.Name = "Moving Average Convergence/Divergence"; this.Description = "Trend-following momentum indicator showing EMA relationship"; this.AddLineSeries("OsMA", Color.Green, 4, LineStyle.Histogramm); this.AddLineLevel(0, "0 level", Color.DarkGreen, 1, LineStyle.Solid); this.AddLineSeries("MACD", Color.DodgerBlue, 1, LineStyle.Solid); this.AddLineSeries("Signal", Color.Red, 1, LineStyle.Solid); this.SeparateWindow = true; } protected override void OnInit() { this.fastEMA = Core.Indicators.BuiltIn.EMA(this.FastPeriod, this.PriceType); this.slowEMA = Core.Indicators.BuiltIn.EMA(this.SlowPeriod, this.PriceType); this.sma = Core.Indicators.BuiltIn.SMA(this.SignalPeriod, PriceType.Close); this.customHD = new HistoricalDataCustom(this); this.customHD.AddIndicator(this.sma); this.AddIndicator(this.fastEMA); this.AddIndicator(this.slowEMA); } protected override void OnUpdate(UpdateArgs args) { if (this.Count < this.MaxEMAPeriod) return; double macdLine = this.fastEMA.GetValue() - this.slowEMA.GetValue(); this.SetValue(macdLine, 1); this.customHD[PriceType.Close, 0] = macdLine; if (this.Count < this.MinHistoryDepths) return; double signal = this.sma.GetValue(); if (double.IsNaN(signal)) return; this.SetValue(signal, 2); this.SetValue(macdLine - signal, 0); } } ``` -------------------------------- ### Implement Relative Strength Index (RSI) Indicator in C# Source: https://context7.com/quantower/scripts/llms.txt This C# code defines the Relative Strength Index (RSI) indicator for Quantower. It calculates RSI based on configurable periods, source prices, and smoothing modes, and visualizes it with overbought/oversold levels. ```csharp using System.Drawing; using TradingPlatform.BusinessLayer; namespace Oscillators; public sealed class IndicatorRelativeStrengthIndex : Indicator, IWatchlistIndicator { [InputParameter("RSI period", 0, 1, 9999)] public int Period = 14; [InputParameter("Sources prices for the RSI line", 1, variants: new object[] { "Close", PriceType.Close, "Open", PriceType.Open, "High", PriceType.High, "Low", PriceType.Low })] public PriceType SourcePrice = PriceType.Close; [InputParameter("Mode for the RSI line", 2, variants: new object[] { "Simple", RSIMode.Simple, "Exponential", RSIMode.Exponential })] public RSIMode SourceRSI = RSIMode.Exponential; [InputParameter("Smoothing period", 5, 1, 9999)] public int MAPeriod = 5; private double prevV = 0.0, prevP = 0.0; private double sumV = 0.0, sumP = 0.0; private Indicator ma; private HistoricalDataCustom histCustom; public int MinHistoryDepths => this.Period + this.MAPeriod; public override string ShortName => $"RSI ({this.Period}: {this.SourcePrice})"; public IndicatorRelativeStrengthIndex() : base() { this.Name = "Relative Strength Index"; this.Description = "Momentum oscillator measuring velocity of directional price movements"; this.AddLineSeries("RSI Line", Color.Green, 1, LineStyle.Solid); this.AddLineSeries("MA Line", Color.PowderBlue, 1, LineStyle.Solid); // Define overbought/oversold levels this.AddLineLevel(70, "Upper Limit", Color.Red, 1, LineStyle.Solid); this.AddLineLevel(30, "Lower Limit", Color.Blue, 1, LineStyle.Solid); this.AddLineLevel(50, "Middle Limit", Color.Gray, 1, LineStyle.Solid); this.SeparateWindow = true; } protected override void OnInit() { this.histCustom = new HistoricalDataCustom(this); this.ma = Core.Indicators.BuiltIn.MA(this.MAPeriod, this.SourcePrice, MaMode.SMA); this.histCustom.AddIndicator(this.ma); } protected override void OnUpdate(UpdateArgs args) { if (args.Reason != UpdateReason.NewTick) { this.prevV = this.sumV; this.prevP = this.sumP; } if (this.Count <= this.Period || this.Period == 0) return; // Calculate RSI using exponential method if (this.Count == this.Period + 1) { CalcSimpleRSI(); this.prevV = this.sumV = this.sumV / this.Period; this.prevP = this.sumP = this.sumP / this.Period; } else { double diff = this.GetPrice(this.SourcePrice) - this.GetPrice(this.SourcePrice, 1); if (diff > 0D) { this.sumV = (this.prevV * (this.Period - 1) + diff) / this.Period; this.sumP = this.prevP * (this.Period - 1) / this.Period; } else { this.sumV = this.prevV * (this.Period - 1) / this.Period; this.sumP = (this.prevP * (this.Period - 1) - diff) / this.Period; } } double rsi = (this.sumP != 0D) ? 100D - 100D / (1.0 + this.sumV / this.sumP) : 0D; this.SetValue(rsi); // Update smoothed RSI line this.histCustom.SetValue(0d, 0d, 0d, this.GetValue()); this.SetValue(this.ma.GetValue(), 1); } private void CalcSimpleRSI() { this.sumV = 0D; this.sumP = 0D; for (int i = 0; i < this.Period; i++) { double diff = this.GetPrice(this.SourcePrice, i) - this.GetPrice(this.SourcePrice, i + 1); if (diff > 0D) this.sumV += diff; else this.sumP -= diff; } } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.