From 707d81ff72b269e4e9a15ef070a1fa2df9a8263d Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Wed, 23 Oct 2024 22:04:21 -0700 Subject: [PATCH] MACD histogram --- docs/indicators/indicators.md | 179 +++++++++++++-------------- docs/styles.css | 33 +++-- lib/volatility/Cmo.cs | 5 - lib/volatility/todo.md | 11 +- quantower/Averages/MacdIndicator.cs | 70 +++++++++-- quantower/IndicatorExtensions.cs | 53 ++++++++ quantower/Volatility/CmoIndicator.cs | 4 +- 7 files changed, 235 insertions(+), 120 deletions(-) diff --git a/docs/indicators/indicators.md b/docs/indicators/indicators.md index b37f75d1..897a417a 100644 --- a/docs/indicators/indicators.md +++ b/docs/indicators/indicators.md @@ -4,95 +4,11 @@ ✔️= Validation tests passed
❌= Issue -|**BASIC TRANSFORMS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady| -|--|:--:|:--:|:--:|:--:|:--:| -|OC2 - Midpoint price|️`.OC2`|CandlePart.OC2|MidPoint|| -|HL2 - Median Price|️`.HL2`|CandlePart.HL2|MedPrice|| -|HLC3 - Typical Price|️`.HLC3`|CandlePart.HLC3|TypPrice|| -|OHL3 - Mean Price|`️.OHL3`|CandlePart.OHL3`||| -|OHLC4 - Average Price|`️.OHLC4`|CandlePart.OHLC4|AvgPrice|| -|HLCC4 - Weighted Price|`️.HLCC4`||WclPrice|| -|
|||| -|**STATISTICS, ERRORS AND NUMERICAL ANALYSIS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady| -|BETA - Beta coefficient||||| -|CORR - Correlation Coefficient||||| -|CURVATURE - Rate of Change in Direction or Slope|`Curvature`|||| -|ENTROPY - Measure of Uncertainty or Disorder|`Entropy`|||| -|KURTOSIS - Measure of Tails/Peakedness|`Kurtosis`|||| -|HUBER - Huber Loss|`Huberloss`|||| -|MAX - Maximum with exponential decay|`Max`|||| -|MAE - Mean Absolute Error|`Mae`|||| -|MAPD - Mean Absolute Percentage Deviation|`Mapd`|||| -|MAPE - Mean Absolute Percentage Error|`Mape`|||| -|MASE - Mean Absolute Scaled Error|`Mase`|||| -|MDA - Mean Directional Accuracy||||| -|ME - Mean Error|`Me`|||| -|MEDIAN - Middle value|`Median`|||| -|MIN - Minimum with exponential decay|`Min`|||| -|MODE - Most Frequent Value|`Mode`|||| -|MPE - Pean Percentage Error|`Mpe`|||| -|MSE - Mean Squared Error|`Mse`|||| -|MSLE - Mean Squared Logarithmic Error|`Msle`|||| -|PERCENTILE - Rank Order|`Percentile`|||| -|RSQUARED - Coefficient of Determination R-Squared||||| -|RAE - Relative Absolute Error|`Rae`|||| -|RMSE - Root Mean Squared Error|`Rmse`|||| -|RSE - Relateive Squared Error|`Rse`|||| -|RMSLE - Root Mean Squared Logarithmic Error|`Rmsle`|||| -|SKEW - Skewness, asymmetry of distribution|`Skew`|||| -|SLOPE - Rate of Change, Linear Regression|`Slope`|||| -|SMAPE - Symmetric Mean Absolute Percentage Error|`Smape`|||| -|STDDEV - Standard Deviation, Measure of Spread|`Stddev`|||| -|THEIL - Theil's U Statistics||||| -|VARIANCE - Average of Squared Deviations|`Variance`|||| -|ZSCORE - Standardized Score|`Zscore`|||| -|
||||| -|**AVERAGES & TRENDS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady| -|AFIRMA - Autoregressive Finite Impulse Response Moving Average|`Afirma`|||| -|ALMA - Arnaud Legoux Moving Average|`Alma`|`✔️`||| -|⭐DEMA - Double EMA Average|`Dema`|`⭐`|`⭐`|`⭐`|| -|DSMA - Deviation Scaled Moving Average|`Dsma`|||| -|DWMA - Double WMA Average|`Dwma`|||| -|⭐EMA - Exponential Moving Average|`Ema`|`⭐`|`⭐`|`⭐`|`⭐`| -|EPMA - Endpoint Moving Average|`Epma`|`✔️`||| -|FRAMA - Fractal Adaptive Moving Average|`Frama`|||| -|FWMA - Fibonacci Weighted Moving Average|`Fwma`|||| -|HILO - Gann High-Low Activator||||| -|HTIT - Hilbert Transform Instantaneous Trendline|`Htit`|`✔️`|`✔️`|| -|GMA - Gaussian-Weighted Moving Average|`Gma`|||| -|HMA - Hull Moving Average|`Hma`|`✔️`||`✔️`| -|HWMA - Holt-Winter Moving Average|`Hwma`|||| -|JMA - Jurik Moving Average|`Jma`|||| -|KAMA - Kaufman's Adaptive Moving Average|`Kama`|`✔️`|`✔️`|`✔️`| -|KDJ - KDJ Indicator (trend reversal)||||| -|LTMA - Laguerre Transform Moving Average|`Ltma`|||| -|MAAF - Median-Average Adaptive Filter|`Maaf`|||| -|MACD - Movign Average Convergence/Divergence||`✔️`|`✔️`|| -|MAMA - MESA Adaptive Moving Average|`Mama`|`✔️`|`✔️`|| -|MGDI - McGinley Dynamic Indicator|`Mgdi`|`✔️`||| -|MMA - Modified Moving Average|`Mma`|||| -|PPMA - Pivot Point Moving Average||||| -|PWMA - Pascal's Weighted Moving Average|`Pwma`|||| -|QEMA - Quad Exponential Moving Average|`Qema`|||| -|RMA - WildeR's Moving Average|`Rma`|||| -|SINEMA - Sine Weighted Moving Average|`Sinema`|||| -|⭐SMA - Simple Moving Average|`Sma`|`⭐`|`⭐`|`⭐`|`⭐`| -|SMMA - Smoothed Moving Average|`Smma`|`✔️`||| -|SSF - Ehler's Super Smoother Filter||||| -|SUPERTREND - Supertrend||`✔️`||| -|T3 - Tillson T3 Moving Average|`T3`|`✔️`|`✔️`|| -|TEMA - Triple EMA Average|`Tema`|`✔️`|`✔️`|`✔️`| -|TRIMA - Triangular Moving Average|`Trima`|`✔️`||`✔️`| -|TSF - Time Series Forecast|||`✔️`|`✔️`| -|VIDYA - Variable Index Dynamic Average|`Vidya`|||`✔️`| -|VORTEX - Vortex Indicator||`✔️`||| -|WMA - Weighted Moving Average|`Wma`|`✔️`||`✔️`| -|ZLEMA - Zero Lag EMA Average|`Zlema`|||`✔️`| -|
|||| -|**VOLATILITY INDICATORS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady| +|**VOLATILITY INDICATORS**|QuanTALib|Skender.Stock|TALib.NETCore| +|--|:--:|:--:|:--:| |ADL - Chaikin Accumulation Distribution Line||GetAdl|Ad|| |ADOSC - Chaikin Accumulation Distribution Oscillator||GetChaikinOsc|AdOsc|| -|ATR - Average True Range||GetAtr|Atr|| +|ATR - Average True Range|`Atr`|GetAtr|Atr|| |ATRP - Average True Range Percent||||| |ATRSTOP - ATR Trailing Stop ||GetAtrStop||| |BBANDS - Bollinger Bands®||BollingerBands||| @@ -114,8 +30,82 @@ |TR - True Range||||| |UI - Ulcer Index||GetUlcerIndex||| |VSTOP - Volatility Stop||GetVolatilityStop||| -|
|||| -|**MOMENTUM INDICATORS & OSCILLATORS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady| +|**NUMERICAL ANALYSIS**|QuanTALib|Skender.Stock|TALib.NETCore| +|BETA - Beta coefficient||||| +|CORR - Correlation Coefficient||||| +|CURVATURE - Rate of Change in Direction or Slope|`Curvature`|||| +|ENTROPY - Measure of Uncertainty or Disorder|`Entropy`|||| +|KURTOSIS - Measure of Tails/Peakedness|`Kurtosis`|||| +|HUBER - Huber Loss|`Huberloss`|||| +|MAX - Maximum with exponential decay|`Max`|||| +|MEDIAN - Middle value|`Median`|||| +|MIN - Minimum with exponential decay|`Min`|||| +|MODE - Most Frequent Value|`Mode`|||| +|PERCENTILE - Rank Order|`Percentile`|||| +|RSQUARED - Coefficient of Determination R-Squared||||| +|SKEW - Skewness, asymmetry of distribution|`Skew`|||| +|SLOPE - Rate of Change, Linear Regression|`Slope`|||| +|STDDEV - Standard Deviation, Measure of Spread|`Stddev`|||| +|THEIL - Theil's U Statistics||||| +|VARIANCE - Average of Squared Deviations|`Variance`|||| +|ZSCORE - Standardized Score|`Zscore`|||| +|**ERRORS**|QuanTALib|Skender.Stock|TALib.NETCore| +|MAE - Mean Absolute Error|`Mae`|||| +|MAPD - Mean Absolute Percentage Deviation|`Mapd`|||| +|MAPE - Mean Absolute Percentage Error|`Mape`|||| +|MASE - Mean Absolute Scaled Error|`Mase`|||| +|MDA - Mean Directional Accuracy||||| +|ME - Mean Error|`Me`|||| +|MPE - Pean Percentage Error|`Mpe`|||| +|MSE - Mean Squared Error|`Mse`|||| +|MSLE - Mean Squared Logarithmic Error|`Msle`|||| +|RAE - Relative Absolute Error|`Rae`|||| +|RMSE - Root Mean Squared Error|`Rmse`|||| +|RSE - Relateive Squared Error|`Rse`|||| +|RMSLE - Root Mean Squared Logarithmic Error|`Rmsle`|||| +|SMAPE - Symmetric Mean Absolute Percentage Error|`Smape`|||| +|**AVERAGES & TRENDS**QuanTALib|Skender.Stock|TALib.NETCore| +|AFIRMA - Autoregressive Finite Impulse Response Moving Average|`Afirma`|||| +|ALMA - Arnaud Legoux Moving Average|`Alma`|`✔️`||| +|⭐DEMA - Double EMA Average|`Dema`|`⭐`|`⭐`|`⭐`|| +|DSMA - Deviation Scaled Moving Average|`Dsma`|||| +|DWMA - Double WMA Average|`Dwma`|||| +|⭐EMA - Exponential Moving Average|`Ema`|`⭐`|`⭐`|`⭐`|`⭐`| +|EPMA - Endpoint Moving Average|`Epma`|`✔️`||| +|FRAMA - Fractal Adaptive Moving Average|`Frama`|||| +|FWMA - Fibonacci Weighted Moving Average|`Fwma`|||| +|HILO - Gann High-Low Activator||||| +|HTIT - Hilbert Transform Instantaneous Trendline|`Htit`|`✔️`|`✔️`|| +|GMA - Gaussian-Weighted Moving Average|`Gma`|||| +|HMA - Hull Moving Average|`Hma`|`✔️`||`✔️`| +|HWMA - Holt-Winter Moving Average|`Hwma`|||| +|JMA - Jurik Moving Average|`Jma`|||| +|KAMA - Kaufman's Adaptive Moving Average|`Kama`|`✔️`|`✔️`|`✔️`| +|KDJ - KDJ Indicator (trend reversal)||||| +|LTMA - Laguerre Transform Moving Average|`Ltma`|||| +|MAAF - Median-Average Adaptive Filter|`Maaf`|||| +|MAMA - MESA Adaptive Moving Average|`Mama`|`✔️`|`✔️`|| +|MGDI - McGinley Dynamic Indicator|`Mgdi`|`✔️`||| +|MMA - Modified Moving Average|`Mma`|||| +|PPMA - Pivot Point Moving Average||||| +|PWMA - Pascal's Weighted Moving Average|`Pwma`|||| +|QEMA - Quad Exponential Moving Average|`Qema`|||| +|RMA - WildeR's Moving Average|`Rma`|||| +|SINEMA - Sine Weighted Moving Average|`Sinema`|||| +|⭐SMA - Simple Moving Average|`Sma`|`⭐`|`⭐`|`⭐`|`⭐`| +|SMMA - Smoothed Moving Average|`Smma`|`✔️`||| +|SSF - Ehler's Super Smoother Filter||||| +|SUPERTREND - Supertrend||`✔️`||| +|T3 - Tillson T3 Moving Average|`T3`|`✔️`|`✔️`|| +|TEMA - Triple EMA Average|`Tema`|`✔️`|`✔️`|`✔️`| +|TRIMA - Triangular Moving Average|`Trima`|`✔️`||`✔️`| +|TSF - Time Series Forecast|||`✔️`|`✔️`| +|VIDYA - Variable Index Dynamic Average|`Vidya`|||`✔️`| +|VORTEX - Vortex Indicator||`✔️`||| +|WMA - Weighted Moving Average|`Wma`|`✔️`||`✔️`| +|ZLEMA - Zero Lag EMA Average|`Zlema`|||`✔️`| + +|**MOMENTUM INDICATORS & OSCILLATORS**|QuanTALib|Skender.Stock|TALib.NETCore| |AC - Acceleration Oscillator||||| |ADX - Average Directional Movement Index||GetAdx|Adx|| |ADXR - Average Directional Movement Index||Rating|Adxr|| @@ -138,6 +128,7 @@ |HURST - Hurst Exponent||GetHurst||| |KRI - Kairi Relative Index||||| |KVO - Klinger Volume Oscillator||GetKvo|||| +|MACD - Movign Average Convergence/Divergence||`✔️`|`✔️`|| |MFI - Money Flow Index||GetMfi||| |MOM - Momentum||||| |NVI - Negative Volume Index||||| @@ -155,8 +146,7 @@ |UO - Ultimate Oscillator||GetUltimate||| |WILLR - Larry Williams' %R||GetWilliamsR||| |WGAT - Williams Alligator||GetAlligator||| -|
|||| -|**VOLUME INDICATORS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady| +|**VOLUME INDICATORS**|QuanTALib|Skender.Stock|TALib.NETCore| |AOBV - Archer On-Balance Volume||||| |CMF - Chaikin Money Flow||GetCmf||| |EOM - Ease of Movement||||| @@ -170,3 +160,10 @@ |VP - Volume Profile||||| |VWAP - Volume Weighted Average Price||GetVwap||| |VWMA - Volume Weighted Moving Average||GetVwma|||| +|**BASIC TRANSFORMS**|QuanTALib|Skender.Stock|TALib.NETCore| +|OC2 - Midpoint price|️`.OC2`|CandlePart.OC2|MidPoint| +|HL2 - Median Price|️`.HL2`|CandlePart.HL2|MedPrice| +|HLC3 - Typical Price|️`.HLC3`|CandlePart.HLC3|TypPrice| +|OHL3 - Mean Price|`️.OHL3`|CandlePart.OHL3| +|OHLC4 - Average Price|`️.OHLC4`|CandlePart.OHLC4|AvgPrice| +|HLCC4 - Weighted Price|`️.HLCC4`||WclPrice| \ No newline at end of file diff --git a/docs/styles.css b/docs/styles.css index f8c34949..143773fa 100644 --- a/docs/styles.css +++ b/docs/styles.css @@ -31,12 +31,12 @@ --base-background-color: var(--mono-base); --base-color: #d3d3d3; --base-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; - --base-font-size: 16px; + --base-font-size: 14px; --base-font-weight: normal; --base-line-height: 1.7; /* Modular Scale */ - --modular-scale: 1.333; + --modular-scale: 1.0; --modular-scale--2: calc(var(--modular-scale--1) / var(--modular-scale)); --modular-scale--1: calc(var(--modular-scale-1) / var(--modular-scale)); --modular-scale-1: 1rem; @@ -313,10 +313,12 @@ body:not([data-platform^=Mac]) * ::-webkit-scrollbar-track{ background:hsla(var(--mono-hue), var(--mono-saturation), 50%, 0.1) } ::-moz-selection{ - background:var(--selection-color) + background: var(--selection-color, #0074d9); + color: #ffffff; } ::selection{ - background:var(--selection-color) + background: var(--selection-color, #0074d9); + color: #ffffff; } .emoji{ height:var(--emoji-size); @@ -629,9 +631,6 @@ pre[data-lang]::selection,pre[data-lang] ::selection,code[class*=lang-]::selecti border-spacing:0; border-collapse:collapse } -.markdown-section th,.markdown-section td{ - padding:var(--table-cell-padding) -} .markdown-section th:not([align]){ text-align:left } @@ -642,14 +641,30 @@ pre[data-lang]::selection,pre[data-lang] ::selection,code[class*=lang-]::selecti background:var(--table-head-background) } .markdown-section th{ - font-weight:var(--table-head-font-weight); - color:var(--strong-color) + font-weight:var(--table-head-font-weight, 700); + color:var(--strong-color); } .markdown-section td{ border-color:var(--table-cell-border-color); border-style:solid; border-width:var(--table-cell-border-width, 0) } +.markdown-section td, +.markdown-section th { + padding:var(--table-cell-padding); + line-height: 1.1; /* Reduced from default 1.7 */ +} +.markdown-section th strong, +.markdown-section th b, +.markdown-section th em, +.markdown-section td strong, +.markdown-section td b, +.markdown-section td em { + font-size: 1.2em; + font-weight: var(--table-head-font-weight, 700); + color: var(--strong-color); + line-height: 2.0; +} .markdown-section tbody{ border-color:var(--table-body-border-color); border-style:solid; diff --git a/lib/volatility/Cmo.cs b/lib/volatility/Cmo.cs index dff9c329..df64d3a9 100644 --- a/lib/volatility/Cmo.cs +++ b/lib/volatility/Cmo.cs @@ -8,8 +8,6 @@ namespace QuanTAlib; /// public class Cmo : AbstractBase { - private readonly int _period; - private readonly CircularBuffer _diffBuffer; private readonly CircularBuffer _sumH; private readonly CircularBuffer _sumL; private double _prevValue, _p_prevValue; @@ -18,9 +16,6 @@ public class Cmo : AbstractBase { if (period < 1) throw new ArgumentOutOfRangeException(nameof(period)); - - _period = period; - _diffBuffer = new(period); _sumH = new(period); _sumL = new(period); diff --git a/lib/volatility/todo.md b/lib/volatility/todo.md index 4a04ca32..32636c3f 100644 --- a/lib/volatility/todo.md +++ b/lib/volatility/todo.md @@ -4,7 +4,12 @@ - **Jurik Volatility (Volty)** - **Standard Deviation** -- **Relative Volatility Index (RVI)** +- **RVI Relative Volatility Index** +- **CMO Chande Momentum Oscillator** +- **Historical Volatility** +- **Average True Range (ATR) (High, Low, Close)** + +- Normalized ATR - Ulcer Index - ARCH/GARCH Models - Exponential Weighted Moving Average (EWMA) Volatility @@ -15,10 +20,6 @@ - Volatility Cone - Bollinger Bands - Stochastic Volatility: Typically modeled using closing prices, but can incorporate other price information - -## OHLC Input (Open, High, Low, Close) - -- **Average True Range (ATR) (High, Low, Close)** - Garman-Klass Volatility - Rogers-Satchell Volatility - Yang-Zhang Volatility diff --git a/quantower/Averages/MacdIndicator.cs b/quantower/Averages/MacdIndicator.cs index 8dca5e31..b8eb4f0b 100644 --- a/quantower/Averages/MacdIndicator.cs +++ b/quantower/Averages/MacdIndicator.cs @@ -1,5 +1,6 @@ using System.Diagnostics.Metrics; using System.Drawing; +using System.Drawing.Drawing2D; using TradingPlatform.BusinessLayer; namespace QuanTAlib; @@ -38,8 +39,11 @@ public class MacdIndicator : Indicator, IWatchlistIndicator private Ema? slow_ma; private Ema? fast_ma; private Ema? signal_ma; + private Slope? histSlope; protected LineSeries? MainSeries; - protected LineSeries? SignalSeries; + protected LineSeries? SignalSeries; + protected LineSeries? HistogramSeries; + protected LineSeries? HistSlopeSeries; protected string? SourceName; public int MinHistoryDepths => Slow; @@ -54,11 +58,16 @@ public class MacdIndicator : Indicator, IWatchlistIndicator SourceName = Source.ToString(); Name = "MACD - Moving Average Convergence Divergence"; Description = "MACD"; - MainSeries = new(name: $"MAIN", color: Color.Yellow, width: 2, style: LineStyle.Solid); - SignalSeries = new(name: $"SIGNAL", color: Color.Blue, width: 2, style: LineStyle.Solid); + MainSeries = new(name: $"MAIN", color: Color.Blue, width: 2, style: LineStyle.Solid); + SignalSeries = new(name: $"SIGNAL", color: Color.Yellow, width: 2, style: LineStyle.Solid); + HistogramSeries = new(name: $"HISTOGRAM", color: Color.White, width: 2, style: LineStyle.Solid); + HistSlopeSeries = new(name: $"SLOPE", color: Color.Transparent, width: 2, style: LineStyle.Solid); + AddLineSeries(MainSeries); AddLineSeries(SignalSeries); + AddLineSeries(HistogramSeries); + AddLineSeries(HistSlopeSeries); } protected override void OnInit() @@ -66,6 +75,7 @@ public class MacdIndicator : Indicator, IWatchlistIndicator slow_ma = new(Slow, useSma: UseSMA); fast_ma = new(Fast, useSma: UseSMA); signal_ma = new(Signal, useSma: UseSMA); + histSlope = new(2); SourceName = Source.ToString(); base.OnInit(); } @@ -76,20 +86,64 @@ public class MacdIndicator : Indicator, IWatchlistIndicator slow_ma!.Calc(input); fast_ma!.Calc(input); double main = fast_ma.Value - slow_ma.Value; - signal_ma!.Calc(main); + double signal = signal_ma!.Calc(main); + double histogram = main - signal; + histSlope!.Calc(histogram); MainSeries!.SetValue(main); MainSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here - SignalSeries!.SetValue(signal_ma.Value); + SignalSeries!.SetValue(signal); SignalSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here + HistogramSeries!.SetValue(histogram); + HistogramSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here + HistSlopeSeries!.SetValue(histSlope.Value); + HistSlopeSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here } +#pragma warning disable CA1416 // Validate platform compatibility public override void OnPaintChart(PaintChartEventArgs args) { - base.OnPaintChart(args); - this.PaintSmoothCurve(args, MainSeries!, slow_ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); + + Graphics gr = args.Graphics; + gr.SmoothingMode = SmoothingMode.AntiAlias; + var mainWindow = this.CurrentChart.Windows[args.WindowIndex]; + var converter = mainWindow.CoordinatesConverter; + var clientRect = mainWindow.ClientRectangle; + + gr.SetClip(clientRect); + DateTime leftTime = new[] { converter.GetTime(clientRect.Left), this.HistoricalData.Time(this!.Count - 1) }.Max(); + DateTime rightTime = new[] { converter.GetTime(clientRect.Right), this.HistoricalData.Time(0) }.Min(); + int leftIndex = (int)this.HistoricalData.GetIndexByTime(leftTime.Ticks) + 1; + int rightIndex = (int)this.HistoricalData.GetIndexByTime(rightTime.Ticks); + + for (int i = rightIndex; i < leftIndex; i++) + { + int barX = (int)converter.GetChartX(this.HistoricalData.Time(i)); + int barY = (int)converter.GetChartY(HistogramSeries![i]); + int barY0 = (int)converter.GetChartY(0); + int HistBarWidth = this.CurrentChart.BarsWidth - 2; + + Brush lowGreen = new SolidBrush(Color.FromArgb(255, 0, 100, 0)); + Brush highGreen = new SolidBrush(Color.FromArgb(255, 50, 255, 50)); + Brush lowRed = new SolidBrush(Color.FromArgb(255, 100, 0, 0)); + Brush highRed = new SolidBrush(Color.FromArgb(255, 255, 50, 50)); + + if (HistogramSeries[i] > 0) + { + Brush col = HistSlopeSeries![i] > 0 ? highGreen : lowGreen; + gr.FillRectangle(col, barX, barY, HistBarWidth, Math.Abs(barY - barY0)); + } + else + { + Brush col = HistSlopeSeries![i] < 0 ? highRed : lowRed; + gr.FillRectangle(col, barX, barY0, HistBarWidth, Math.Abs(barY0 - barY)); + } + + } + + this.PaintSmoothCurve(args, MainSeries!, slow_ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.3); this.PaintSmoothCurve(args, SignalSeries!, slow_ma!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); - this.DrawText(args, Description); + base.OnPaintChart(args); } } diff --git a/quantower/IndicatorExtensions.cs b/quantower/IndicatorExtensions.cs index 90d37e1f..5c9a79dc 100644 --- a/quantower/IndicatorExtensions.cs +++ b/quantower/IndicatorExtensions.cs @@ -8,6 +8,12 @@ public enum SourceType { Open, High, Low, Close, HL2, OC2, OHL3, HLC3, OHLC4, HLCC4 } + +public enum MaType +{ + Alma, Dema, Dsma, Dwma, Ema, Epma, Frama, Fwma, Gma, Hma, Hwma, Jma, Kama, Maaf, Mgdi, MMa, Pwma, Rema, Rma, Sinema, Sma, Smma, T3, Tema, Trima, Vidya, Wma, Zlema +} + public static class IndicatorExtensions { public static TValue GetInputValue(this Indicator indicator, UpdateArgs args, SourceType source) @@ -131,6 +137,53 @@ public static class IndicatorExtensions } } } + + public static void PaintHistogram(this Indicator indicator, PaintChartEventArgs args, LineSeries series, int warmupPeriod, bool showColdValues = true) + { + if (!series.Visible || indicator.CurrentChart == null) + return; + + Graphics gr = args.Graphics; + gr.SmoothingMode = SmoothingMode.AntiAlias; + var mainWindow = indicator.CurrentChart.Windows[args.WindowIndex]; + var converter = mainWindow.CoordinatesConverter; + var clientRect = mainWindow.ClientRectangle; + + gr.SetClip(clientRect); + DateTime leftTime = new[] { converter.GetTime(clientRect.Left), indicator.HistoricalData.Time(indicator!.Count - 1) }.Max(); + DateTime rightTime = new[] { converter.GetTime(clientRect.Right), indicator.HistoricalData.Time(0) }.Min(); + int leftIndex = (int)indicator.HistoricalData.GetIndexByTime(leftTime.Ticks) + 1; + int rightIndex = (int)indicator.HistoricalData.GetIndexByTime(rightTime.Ticks); + + for (int i = rightIndex; i < leftIndex; i++) + { + int barX = (int)converter.GetChartX(indicator.HistoricalData.Time(i)); + int barY = (int)converter.GetChartY(series[i]); + int barY0 = (int)converter.GetChartY(0); + int HistBarWidth = indicator.CurrentChart.BarsWidth - 2; + + if (series[i] > 0) + { + using (Brush hist = new SolidBrush(Color.FromArgb(150, 0, 255, 0))) + { + gr.FillRectangle(hist, barX, barY, HistBarWidth, Math.Abs(barY - barY0)); + + } + } + else + { + using (Brush hist = new SolidBrush(Color.FromArgb(150, 255, 0, 0))) + { + gr.FillRectangle(hist, barX, barY0, HistBarWidth, Math.Abs(barY0 - barY)); + + } + } + + } + + } + + public static void DrawText(this Indicator indicator, PaintChartEventArgs args, string text) { if (indicator.CurrentChart == null) diff --git a/quantower/Volatility/CmoIndicator.cs b/quantower/Volatility/CmoIndicator.cs index c539aeec..6a7a069d 100644 --- a/quantower/Volatility/CmoIndicator.cs +++ b/quantower/Volatility/CmoIndicator.cs @@ -65,8 +65,8 @@ public class CmoIndicator : Indicator, IWatchlistIndicator { base.OnPaintChart(args); this.PaintHLine(args, 0, new Pen(Color.DarkGray, width: 1)); - this.PaintHLine(args, 50, new Pen(Color.DarkRed, width: 1)); - this.PaintHLine(args, -50, new Pen(Color.DarkGreen, width: 1)); + this.PaintHLine(args, 50, new Pen(Color.Blue, width: 1)); + this.PaintHLine(args, -50, new Pen(Color.Blue, width: 1)); this.PaintSmoothCurve(args, CmoSeries!, cmo!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2); } }