+semver: feature Cmo, Macd, Rsi, Rsx

This commit is contained in:
Miha Kralj
2024-10-24 18:37:08 -07:00
36 changed files with 3536 additions and 524 deletions
+3 -3
View File
@@ -25,7 +25,7 @@ public class BarIndicatorTests
private static readonly ITValue[] indicators = new ITValue[]
{
new Atr(period: 14),
new Jvolty(period: 14)
// Add other TBar-based indicators here
};
@@ -80,14 +80,14 @@ public class BarIndicatorTests
if (methods.Count > 0)
{
// Prefer the method with TBar parameter
var method = methods.FirstOrDefault(m =>
var method = methods.Find(m =>
{
var parameters = m.GetParameters();
return parameters.Length == 1 && parameters[0].ParameterType == typeof(TBar);
});
// If not found, return the first method
return method ?? methods.First();
return method ?? methods[0];
}
type = type.BaseType!;
+1 -2
View File
@@ -13,7 +13,7 @@ namespace QuanTAlib
{
public class QuantowerTests
{
private void TestIndicator<T>(string fieldName = "ma") where T : Indicator, new()
private static void TestIndicator<T>(string fieldName = "ma") where T : Indicator, new()
{
var indicator = new T();
try
@@ -95,7 +95,6 @@ namespace QuanTAlib
// Volatility Indicators
[Fact] public void Atr() => TestIndicator<AtrIndicator>("atr");
[Fact] public void Jvolty() => TestIndicator<JvoltyIndicator>("jvolty");
[Fact] public void Historical() => TestIndicator<HistoricalIndicator>("historical");
[Fact] public void Realized() => TestIndicator<RealizedIndicator>("realized");
+1 -1
View File
@@ -345,7 +345,7 @@ public class SkenderTests
var atrValues = quotes.GetAtr(lookbackPeriods: period).Select(i => i.Atr.Null2NaN()!);
const int AdditionalPeriods = 500;
for (int i = QL.Length - 1; i > period + AdditionalPeriods; i--)
for (int i = QL.Length - 1; i > 1000 + AdditionalPeriods; i--)
{
Assert.InRange(atrValues.ElementAt(i) - QL[i].Value, -range, range);
}
-15
View File
@@ -57,21 +57,6 @@ public class VolatilityUpdateTests
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Jvolty_Update()
{
var indicator = new Jvolty(period: 14);
double initialValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: true));
for (int i = 0; i < RandomUpdates; i++)
{
indicator.Calc(GetRandomBar(false));
}
double finalValue = indicator.Calc(new TBar(DateTime.Now, ReferenceValue, ReferenceValue, ReferenceValue, ReferenceValue, 1000, IsNew: false));
Assert.Equal(initialValue, finalValue, precision);
}
[Fact]
public void Realized_Update()
{
+134
View File
@@ -0,0 +1,134 @@
AC,Acceleration Oscillator
AD,Chaikin A/D Line
ADOSC,Chaikin A/D Oscillator
ADL,Accumulation / Distribution Line
ADX,Average Directional Movement Index
ADXR,Average Directional Movement Index Rating
Alligator,Alligator Indicator
ALMA,Arnaud Legoux Moving Average
AO,Awesome Oscillator
APO,Absolute Price Oscillator
AROON,Aroon Indicator
AROONOSC,Aroon Oscillator
ATS,ATR Trailing Stop
ATR,Average True Range
AVGPRICE,Average Price
BB,Bollinger Bands
BBF,Bollinger Bands Flat
BBP,Bull and Bear Power
BC,Beta Coefficient
BETA,Beta
BOP,Balance of Power
CCI,Commodity Channel Index
CE,Chandelier Exit
Channel,Price Channel
CI,Choppiness Index
CMF,Chaikin Money Flow
CMO,Chande Momentum Oscillator
CORREL,Pearson's Correlation Coefficient
CRSI,ConnorsRSI
DC,Donchian Channels
DCP,Dominant Cycle Periods
DEMA,Double Exponential Moving Average
DMI,Directional Movement Index
DPO,Detrended Price Oscillator
DX,Directional Movement Index
EMA,Exponential Moving Average
EPMA,Endpoint Moving Average
ERI,Elder-ray Index
FCB,Fractal Chaos Bands
FI,Force Index
GO,Gator Oscillator
HE,Hurst Exponent
HMA,Hull Moving Average
HT_TRENDLINE,Hilbert Transform - Instantaneous Trendline
HT_TRENDMODE,Hilbert Transform - Trend vs Cycle Mode
HV,Historical Volatility
IC,Ichimoku Cloud
KAMA,Kaufman Adaptive Moving Average
KDJ,KDJ Index
Keltner,Keltner Channel
KVO,Klinger Volume Oscillator
LINEARREG,Linear Regression
LINEARREG_ANGLE,Linear Regression Angle
LINEARREG_INTERCEPT,Linear Regression Intercept
LINEARREG_SLOPE,Linear Regression Slope
LSMA,Least Squares Moving Average
LWMA,Linearly Weighted Moving Average
MACDEXT,MACD with controllable MA type
MACDFIX,Moving Average Convergence Divergence Fix 12/26
MAD,Mean absolute deviation
MAE,Moving Average Envelope
MAMA,MESA Adaptive Moving Average
MAPE,Mean absolute percentage error
MAX,Highest value over a specified period
MAXINDEX,Index of highest value over a specified period
MD,McGinley Dynamic
MEDPRICE,Median Price
MFI,Money Flow Index
MIN,Lowest value over a specified period
MININDEX,Index of lowest value over a specified period
MINMAX,Lowest and highest values over a specified period
MINMAXINDEX,Indexes of lowest and highest values over a period
MMA,Modified Moving Average
MOM,Momentum
MSE,Mean square error
NATR,Normalized Average True Range
OBV,On Balance Volume
OsMA,Moving Average of Oscillator
PAZ,Price Action Zones
Pivots,Pivots
PMO,Price Momentum Oscillator
PP,Pivot Points
PPO,Percentage Price Oscillator
PPMA,Pivot Point Moving Average
PRS,Price Relative Strength
PVI,Positive Volume Index
PVO,Percentage Volume Oscillator
Qstick,Qstick Indicator
R2,R-Squared (Coefficient of Determination)
Regression,Regression Line Indicator
RLW,%R Larry Williams
RMA,Running Moving Average
ROC,Rate of Change
ROCB,ROC with Bands
RPP,Rolling Pivot Points
RRA,Rescaled Range Analysis
RSI,Relative Strength Index
SAR,Parabolic SAR
SAREXT,Parabolic SAR - Extended
SDC,Standard Deviation Channels
SI,Swing Index
SLR,Slope and Linear Regression
SMA,Simple Moving Average
SMI,Stochastic Momentum Index
SMMA,Smoothed Moving Average
ST,SuperTrend
STARC,STARC Bands
STC,Schaff Trend Cycle
STDDEV,Standard Deviation
STOCH,Stochastic
STOCHF,Stochastic Fast
STOCHRSI,Stochastic Relative Strength Index
SUM,Summation
T3,Triple Exponential Moving Average (T3)
TEMA,Triple Exponential Moving Average
TRANGE,True Range
TRIMA,Triangular Moving Average
TRIX,1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
TSI,True Strength Index
TYPPRICE,Typical Price
UI,Ulcer Index
ULTOSC,Ultimate Oscillator
VAR,Variance
VI,Vortex Indicator
Volume,Volume Indicator
VS,Volatility Stop
VWAP,Volume Weighted Average Price
VWMA,Volume Weighted Moving Average
WA,Williams Alligator
WCLPRICE,Weighted Close Price
WF,Williams Fractal
WMA,Weighted Moving Average
ZS,Z-Score
ZZ,ZigZag Indicator
1 AC Acceleration Oscillator
2 AD Chaikin A/D Line
3 ADOSC Chaikin A/D Oscillator
4 ADL Accumulation / Distribution Line
5 ADX Average Directional Movement Index
6 ADXR Average Directional Movement Index Rating
7 Alligator Alligator Indicator
8 ALMA Arnaud Legoux Moving Average
9 AO Awesome Oscillator
10 APO Absolute Price Oscillator
11 AROON Aroon Indicator
12 AROONOSC Aroon Oscillator
13 ATS ATR Trailing Stop
14 ATR Average True Range
15 AVGPRICE Average Price
16 BB Bollinger Bands
17 BBF Bollinger Bands Flat
18 BBP Bull and Bear Power
19 BC Beta Coefficient
20 BETA Beta
21 BOP Balance of Power
22 CCI Commodity Channel Index
23 CE Chandelier Exit
24 Channel Price Channel
25 CI Choppiness Index
26 CMF Chaikin Money Flow
27 CMO Chande Momentum Oscillator
28 CORREL Pearson's Correlation Coefficient
29 CRSI ConnorsRSI
30 DC Donchian Channels
31 DCP Dominant Cycle Periods
32 DEMA Double Exponential Moving Average
33 DMI Directional Movement Index
34 DPO Detrended Price Oscillator
35 DX Directional Movement Index
36 EMA Exponential Moving Average
37 EPMA Endpoint Moving Average
38 ERI Elder-ray Index
39 FCB Fractal Chaos Bands
40 FI Force Index
41 GO Gator Oscillator
42 HE Hurst Exponent
43 HMA Hull Moving Average
44 HT_TRENDLINE Hilbert Transform - Instantaneous Trendline
45 HT_TRENDMODE Hilbert Transform - Trend vs Cycle Mode
46 HV Historical Volatility
47 IC Ichimoku Cloud
48 KAMA Kaufman Adaptive Moving Average
49 KDJ KDJ Index
50 Keltner Keltner Channel
51 KVO Klinger Volume Oscillator
52 LINEARREG Linear Regression
53 LINEARREG_ANGLE Linear Regression Angle
54 LINEARREG_INTERCEPT Linear Regression Intercept
55 LINEARREG_SLOPE Linear Regression Slope
56 LSMA Least Squares Moving Average
57 LWMA Linearly Weighted Moving Average
58 MACDEXT MACD with controllable MA type
59 MACDFIX Moving Average Convergence Divergence Fix 12/26
60 MAD Mean absolute deviation
61 MAE Moving Average Envelope
62 MAMA MESA Adaptive Moving Average
63 MAPE Mean absolute percentage error
64 MAX Highest value over a specified period
65 MAXINDEX Index of highest value over a specified period
66 MD McGinley Dynamic
67 MEDPRICE Median Price
68 MFI Money Flow Index
69 MIN Lowest value over a specified period
70 MININDEX Index of lowest value over a specified period
71 MINMAX Lowest and highest values over a specified period
72 MINMAXINDEX Indexes of lowest and highest values over a period
73 MMA Modified Moving Average
74 MOM Momentum
75 MSE Mean square error
76 NATR Normalized Average True Range
77 OBV On Balance Volume
78 OsMA Moving Average of Oscillator
79 PAZ Price Action Zones
80 Pivots Pivots
81 PMO Price Momentum Oscillator
82 PP Pivot Points
83 PPO Percentage Price Oscillator
84 PPMA Pivot Point Moving Average
85 PRS Price Relative Strength
86 PVI Positive Volume Index
87 PVO Percentage Volume Oscillator
88 Qstick Qstick Indicator
89 R2 R-Squared (Coefficient of Determination)
90 Regression Regression Line Indicator
91 RLW %R Larry Williams
92 RMA Running Moving Average
93 ROC Rate of Change
94 ROCB ROC with Bands
95 RPP Rolling Pivot Points
96 RRA Rescaled Range Analysis
97 RSI Relative Strength Index
98 SAR Parabolic SAR
99 SAREXT Parabolic SAR - Extended
100 SDC Standard Deviation Channels
101 SI Swing Index
102 SLR Slope and Linear Regression
103 SMA Simple Moving Average
104 SMI Stochastic Momentum Index
105 SMMA Smoothed Moving Average
106 ST SuperTrend
107 STARC STARC Bands
108 STC Schaff Trend Cycle
109 STDDEV Standard Deviation
110 STOCH Stochastic
111 STOCHF Stochastic Fast
112 STOCHRSI Stochastic Relative Strength Index
113 SUM Summation
114 T3 Triple Exponential Moving Average (T3)
115 TEMA Triple Exponential Moving Average
116 TRANGE True Range
117 TRIMA Triangular Moving Average
118 TRIX 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA
119 TSI True Strength Index
120 TYPPRICE Typical Price
121 UI Ulcer Index
122 ULTOSC Ultimate Oscillator
123 VAR Variance
124 VI Vortex Indicator
125 Volume Volume Indicator
126 VS Volatility Stop
127 VWAP Volume Weighted Average Price
128 VWMA Volume Weighted Moving Average
129 WA Williams Alligator
130 WCLPRICE Weighted Close Price
131 WF Williams Fractal
132 WMA Weighted Moving Average
133 ZS Z-Score
134 ZZ ZigZag Indicator
+313 -5
View File
@@ -1,5 +1,313 @@
# Backlog and done
|**QT**|**Chart**|Cmnt|Docs|isNew|Validation|
|--|:--:|:--:|:--:|:--:|:--:|
|AFIRMA|✔️|||||
| AD | Chaikin A/D Line |
| AROON | Aroon Indicator |
| ADX | Average Directional Movement Index |
| ADXR | Average Directional Movement Index Rating |
| DX | Directional Movement Index |
| SAR | Parabolic SAR |
| SAREXT | Parabolic SAR - Extended |
| HT_TRENDLINE | Hilbert Transform - Instantaneous Trendline |
| HT_TRENDMODE | Hilbert Transform - Trend vs Cycle Mode |
| ZZ | ZigZag Indicator |
| DMI | Directional Movement Index |
| Alligator | Alligator Indicator |
| Regression | Regression Line Indicator |
| SI | Swing Index |
| ATS | ATR Trailing Stop |
| ERI | Elder-ray Index |
| GO | Gator Oscillator |
| HE | Hurst Exponent |
| IC | Ichimoku Cloud |
| ST | SuperTrend |
| VI | Vortex Indicator |
| WA | Williams Alligator |
| RSI | Relative Strength Index |
| CCI | Commodity Channel Index |
| MOM | Momentum |
| ROC | Rate of Change |
| PPO | Percentage Price Oscillator |
| AO | Awesome Oscillator |
| CMO | Chande Momentum Oscillator |
| TRIX | 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA |
| ULTOSC | Ultimate Oscillator |
| AROONOSC | Aroon Oscillator |
| ADOSC | Chaikin A/D Oscillator |
| APO | Absolute Price Oscillator |
| STOCH | Stochastic |
| STOCHF | Stochastic Fast |
| STOCHRSI | Stochastic Relative Strength Index |
| Qstick | Qstick Indicator |
| RLW | %R Larry Williams |
| AC | Acceleration Oscillator |
| TSI | True Strength Index |
| CRSI | ConnorsRSI |
| DPO | Detrended Price Oscillator |
| KDJ | KDJ Index |
| STC | Schaff Trend Cycle |
| SMI | Stochastic Momentum Index |
| BB | Bollinger Bands |
| Keltner | Keltner Channel |
| BBF | Bollinger Bands Flat |
| Channel | Price Channel |
| MAE | Moving Average Envelope |
| PAZ | Price Action Zones |
| DC | Donchian Channels |
| FCB | Fractal Chaos Bands |
| PP | Pivot Points |
| RPP | Rolling Pivot Points |
| STARC | STARC Bands |
| SDC | Standard Deviation Channels |
| OBV | On Balance Volume |
| PVI | Positive Volume Index |
| Volume | Volume Indicator |
| MFI | Money Flow Index |
| ADL | Accumulation / Distribution Line |
| CMF | Chaikin Money Flow |
| FI | Force Index |
| KVO | Klinger Volume Oscillator |
| PVO | Percentage Volume Oscillator |
| ATS | ATR Trailing Stop |
| CE | Chandelier Exit |
| SAR | Parabolic SAR |
| ST | SuperTrend |
| VS | Volatility Stop |
| Pivots | Pivots |
| WF | Williams Fractal |
| EMA | Exponential Moving Average |
| SMA | Simple Moving Average |
| LWMA | Linearly Weighted Moving Average |
| SMMA | Smoothed Moving Average |
| MMA | Modified Moving Average |
| KAMA | Kaufman Adaptive Moving Average |
| DEMA | Double Exponential Moving Average |
| TEMA | Triple Exponential Moving Average |
| MAMA | MESA Adaptive Moving Average |
| TRIMA | Triangular Moving Average |
| T3 | Triple Exponential Moving Average (T3) |
| PPMA | Pivot Point Moving Average |
| WMA | Weighted Moving Average |
| ALMA | Arnaud Legoux Moving Average |
| EPMA | Endpoint Moving Average |
| HMA | Hull Moving Average |
| LSMA | Least Squares Moving Average |
| MD | McGinley Dynamic |
| RMA | Running Moving Average |
| VWAP | Volume Weighted Average Price |
| VWMA | Volume Weighted Moving Average |
| ATR | Average True Range |
| NATR | Normalized Average True Range |
| TRANGE | True Range |
| STDDEV | Standard Deviation |
| HV | Historical Volatility |
| BOP | Balance of Power |
| BBP | Bull and Bear Power |
| CI | Choppiness Index |
| DCP | Dominant Cycle Periods |
| PMO | Price Momentum Oscillator |
| PRS | Price Relative Strength |
| ROCB | ROC with Bands |
| RRA | Rescaled Range Analysis |
| UI | Ulcer Index |
| CORREL | Pearson's Correlation Coefficient |
| BETA | Beta |
| VAR | Variance |
| AVGPRICE | Average Price |
| MEDPRICE | Median Price |
| TYPPRICE | Typical Price |
| WCLPRICE | Weighted Close Price |
| SUM | Summation |
| MAX | Highest value over a specified period |
| MIN | Lowest value over a specified period |
| MAXINDEX | Index of highest value over a specified period |
| MININDEX | Index of lowest value over a specified period |
| MINMAX | Lowest and highest values over a specified period |
| MINMAXINDEX | Indexes of lowest and highest values over a period |
| BC | Beta Coefficient |
| MAD | Mean absolute deviation |
| MAPE | Mean absolute percentage error |
| MSE | Mean square error |
| R2 | R-Squared (Coefficient of Determination) |
| SLR | Slope and Linear Regression |
| ZS | Z-Score |
| AD | Chaikin A/D Line |
| AROON | Aroon Indicator |
| ADX | Average Directional Movement Index |
| ADXR | Average Directional Movement Index Rating |
| DX | Directional Movement Index |
| SAR | Parabolic SAR |
| SAREXT | Parabolic SAR - Extended |
| HT_TRENDLINE | Hilbert Transform - Instantaneous Trendline |
| HT_TRENDMODE | Hilbert Transform - Trend vs Cycle Mode |
| ZZ | ZigZag Indicator |
| DMI | Directional Movement Index |
| Alligator | Alligator Indicator |
| Regression | Regression Line Indicator |
| SI | Swing Index |
| ATS | ATR Trailing Stop |
| ERI | Elder-ray Index |
| GO | Gator Oscillator |
| HE | Hurst Exponent |
| IC | Ichimoku Cloud |
| ST | SuperTrend |
| VI | Vortex Indicator |
| WA | Williams Alligator |
| RSI | Relative Strength Index |
| CCI | Commodity Channel Index |
| MOM | Momentum |
| ROC | Rate of Change |
| PPO | Percentage Price Oscillator |
| AO | Awesome Oscillator |
| CMO | Chande Momentum Oscillator |
| TRIX | 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA |
| ULTOSC | Ultimate Oscillator |
| AROONOSC | Aroon Oscillator |
| ADOSC | Chaikin A/D Oscillator |
| APO | Absolute Price Oscillator |
| STOCH | Stochastic |
| STOCHF | Stochastic Fast |
| STOCHRSI | Stochastic Relative Strength Index |
| Qstick | Qstick Indicator |
| RLW | %R Larry Williams |
| AC | Acceleration Oscillator |
| TSI | True Strength Index |
| CRSI | ConnorsRSI |
| DPO | Detrended Price Oscillator |
| KDJ | KDJ Index |
| STC | Schaff Trend Cycle |
| SMI | Stochastic Momentum Index |
| BB | Bollinger Bands |
| Keltner | Keltner Channel |
| BBF | Bollinger Bands Flat |
| Channel | Price Channel |
| MAE | Moving Average Envelope |
| PAZ | Price Action Zones |
| DC | Donchian Channels |
| FCB | Fractal Chaos Bands |
| PP | Pivot Points |
| RPP | Rolling Pivot Points |
| STARC | STARC Bands |
| SDC | Standard Deviation Channels |
| OBV | On Balance Volume |
| PVI | Positive Volume Index |
| Volume | Volume Indicator |
| MFI | Money Flow Index |
| ADL | Accumulation / Distribution Line |
| CMF | Chaikin Money Flow |
| FI | Force Index |
| KVO | Klinger Volume Oscillator |
| PVO | Percentage Volume Oscillator |
| ATS | ATR Trailing Stop |
| CE | Chandelier Exit |
| SAR | Parabolic SAR |
| ST | SuperTrend |
| VS | Volatility Stop |
| Pivots | Pivots |
| WF | Williams Fractal |
| ALMA | Arnaud Legoux Moving Average |
| EPMA | Endpoint Moving Average |
| HMA | Hull Moving Average |
| LSMA | Least Squares Moving Average |
| MD | McGinley Dynamic |
| RMA | Running Moving Average |
| T3 | Tillson T3 Moving Average |
| VWAP | Volume Weighted Average Price |
| VWMA | Volume Weighted Moving Average |
| BOP | Balance of Power |
| BBP | Bull and Bear Power |
| CI | Choppiness Index |
| DCP | Dominant Cycle Periods |
| PMO | Price Momentum Oscillator |
| PRS | Price Relative Strength |
| ROCB | ROC with Bands |
| RRA | Rescaled Range Analysis |
| UI | Ulcer Index |
| BC | Beta Coefficient |
| MAD | Mean absolute deviation |
| MAPE | Mean absolute percentage error |
| MSE | Mean square error |
| R2 | R-Squared (Coefficient of Determination) |
| SLR | Slope and Linear Regression |
| ZS | Z-Score |
| EMA | Exponential Moving Average |
| SMA | Simple Moving Average |
| LWMA | Linearly Weighted Moving Average |
| SMMA | Smoothed Moving Average |
| MMA | Modified Moving Average |
| KAMA | Kaufman Adaptive Moving Average |
| DEMA | Double Exponential Moving Average |
| TEMA | Triple Exponential Moving Average |
| MAMA | MESA Adaptive Moving Average |
| TRIMA | Triangular Moving Average |
| T3 | Triple Exponential Moving Average (T3) |
| PPMA | Pivot Point Moving Average |
| MAE | Moving Average Envelope |
| MACD | Moving Average Convergence Divergence |
| MACDEXT | MACD with controllable MA type |
| MACDFIX | Moving Average Convergence Divergence Fix 12/26 |
| OsMA | Moving Average of Oscillator |
| Regression | Regression Indicator |
| LINEARREG | Linear Regression |
| LINEARREG_ANGLE | Linear Regression Angle |
| LINEARREG_INTERCEPT | Linear Regression Intercept |
| LINEARREG_SLOPE | Linear Regression Slope |
| RSI | Relative Strength Index |
| CCI | Commodity Channel Index |
| MOM | Momentum |
| ROC | Rate of Change |
| PPO | Percentage Price Oscillator |
| AO | Awesome Oscillator |
| CMO | Chande Momentum Oscillator |
| TRIX | 1-day Rate-Of-Change (ROC) of a Triple Smooth EMA |
| ULTOSC | Ultimate Oscillator |
| AROONOSC | Aroon Oscillator |
| ADOSC | Chaikin A/D Oscillator |
| APO | Absolute Price Oscillator |
| STOCH | Stochastic |
| STOCHF | Stochastic Fast |
| STOCHRSI | Stochastic Relative Strength Index |
| Qstick | Qstick Indicator |
| RLW | %R Larry Williams |
| AC | Acceleration Oscillator |
| TSI | True Strength Index |
| AD | Chaikin A/D Line |
| AROON | Aroon Indicator |
| ADX | Average Directional Movement Index |
| ADXR | Average Directional Movement Index Rating |
| DX | Directional Movement Index |
| SAR | Parabolic SAR |
| SAREXT | Parabolic SAR - Extended |
| HT_TRENDLINE | Hilbert Transform - Instantaneous Trendline |
| HT_TRENDMODE | Hilbert Transform - Trend vs Cycle Mode |
| ZZ | ZigZag Indicator |
| DMI | Directional Movement Index |
| Alligator | Alligator Indicator |
| Regression | Regression Line Indicator |
| SI | Swing Index |
| ATR | Average True Range |
| NATR | Normalized Average True Range |
| TRANGE | True Range |
| STDDEV | Standard Deviation |
| HV | Historical Volatility |
| BB | Bollinger Bands |
| Keltner | Keltner Channel |
| BBF | Bollinger Bands Flat |
| Channel | Price Channel |
| MAE | Moving Average Envelope |
| PAZ | Price Action Zones |
| OBV | On Balance Volume |
| PVI | Positive Volume Index |
| Volume | Volume Indicator |
| MFI | Money Flow Index |
| CORREL | Pearson's Correlation Coefficient |
| BETA | Beta |
| VAR | Variance |
| AVGPRICE | Average Price |
| MEDPRICE | Median Price |
| TYPPRICE | Typical Price |
| WCLPRICE | Weighted Close Price |
| SUM | Summation |
| MAX | Highest value over a specified period |
| MIN | Lowest value over a specified period |
| MAXINDEX | Index of highest value over a specified period |
| MININDEX | Index of lowest value over a specified period |
| MINMAX | Lowest and highest values over a specified period |
| MINMAXINDEX | Indexes of lowest and highest values over a period |
+34 -10
View File
@@ -1,7 +1,34 @@
* [QuanTAlib](/)
* [Home](/)
* Introduction
* [Overview]()
* [Features]()
* [Historical vs Real-time analysis](essays/realtime.md)
* [Indicators](indicators/indicators.md)
* Averages & Trends
* Core Concepts
* [Time Series Data Handling]()
* [Calculation classes]()
* [Presentation Classes]()
* QuanTAlib C# Library
* [Installation]()
* [Quick Start Guide]()
* [Usage Examples]()
* [Tests and Validation]()
* Quantower Charts
* [Installation]()
* [Quick Start Guide]()
* [Using VS Code for QuanTower coding](setup/vscode.md)
* [Using DotPeek](setup/dotpeek.md)
* [Creating Custom Indicators]()
* [Inspecting Quantower Internals]()
* [Available Indicators](indicators/indicators.md)
* Basic Transforms
* Numerical Analysis
* Errors
* Moving Averages
* [AFIRMA - Adaptive Filtering Integrated Recursive Moving Average](indicators/averages/afirma/afirma.md)
* [Calculation](indicators/averages/afirma/calc.md)
* [Analysis](indicators/averages/afirma/analysis.md)
@@ -14,7 +41,6 @@
* [Calculation](indicators/averages/ama/calc.md)
* [Analysis](indicators/averages/ama/analysis.md)
* [Charts](indicators/averages/ama/charts.md)
* [Convolutiuon]
* [DEMA - Double Exponential Moving Average](indicators/averages/dema/dema.md)
* [Calculation](indicators/averages/dema/calc.md)
* [Analysis](indicators/averages/dema/analysis.md)
@@ -61,11 +87,9 @@
* VIDYA - Variable Index Dynamic Average
* WMA - Weighted Moving Average
* ZLEMA - Weighted Moving Average
* Basic Data Transforms
* [Statistics & Numerical Analysis](indicators/statistics/list.md)
* Trends
* Momentum
* Oscillators
* Volatility
* Volume
* Momentum & Oscillators
* Development
* [VS Code](setup/vscode.md)
* [DotPeek](setup/dotpeek.md)
+46 -69
View File
@@ -2,76 +2,38 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<title>QuanTAlib Documentation</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="description" content="Description">
<meta name="description" content="Documentation for QuanTAlib, a quantitative technical analysis library">
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/css/theme-simple-dark.css" integrity="sha384-G+RAlt+LEfAH/nY+DZh3+XIhRboypMI32hiJ9BwnmjF41May5BWQKyrDrEkNdV/i" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/katex.min.css" integrity="sha384-3UiQGuEI4TTMaFmGIZumfRPtfKQ3trwQE2JgosJxCnGmQpL/lJdjpcHkaaFwHlcI" crossorigin="anonymous">
<style>
.markdown-section {
max-width: none !important;
width: 100% !important;
}
.sidebar-nav {
line-height: 1.5;
font-size: 12px;
}
.markdown-section table tbody td {
padding: 4px 1px;
}
:root {
--sidebar-width: 350px;
--sidebar-nav-link-padding: 2px 0;
--sidebar-nav-pagelink-padding: 2px 0 2px 12px;
--sidebar-nav-indent: 12px;
}
.content {
left: var(--sidebar-width);
}
.sidebar-toggle {
width: var(--sidebar-width);
}
/* Updated styles for partially expandable sidebar */
.sidebar-nav ul ul ul ul {
overflow: hidden;
max-height: 0;
transition: max-height 0.3s ease-out;
}
.sidebar-nav ul ul ul li:hover > ul {
max-height: 1000px;
transition: max-height 0.3s ease-in;
}
.sidebar-nav .collapse.level-4 > ul {
max-height: 0 !important;
}
.sidebar-nav .collapse.level-4:hover > ul {
max-height: 1000px !important;
}
.sidebar-nav .folder > .app-sub-sidebar {
display: block !important;
}
/* Ensure levels 1, 2, and 3 are always visible */
.sidebar-nav > ul,
.sidebar-nav > ul > li > ul,
.sidebar-nav > ul > li > ul > li > ul {
max-height: none !important;
overflow: visible !important;
}
</style>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'QuanTAlib',
repo: 'https://github.com/mihakralj/quantalib',
homepage: 'readme.md',
loadSidebar: true,
subMaxLevel: 4, // Increased to allow for level 4+ items
name: '',
repo: '',
sidebarDisplayLevel: 3, // Changed to keep levels 1, 2, and 3 expanded
auto2top: true,
mergeNavbar: true,
sidebarDisplayLevel: 0, // Add this line to collapse all sidebar items initially
search: {
maxAge: 86400000,
paths: 'auto',
placeholder: 'Type to search',
noData: 'No Results!',
depth: 6,
hideOtherSidebarContent: false,
},
pagination: {
previousText: 'Previous',
nextText: 'Next',
crossChapter: true,
crossChapterText: true,
},
themeable: {
readyTransition: true,
responsiveTables: true
@@ -79,18 +41,33 @@
latex: {
inlineMath: [['$', '$'], ['\\(', '\\)']],
displayMath: [['$$', '$$']],
}
},
executeScript: true,
externalLinkTarget: '_blank',
cornerExternalLinkTarget: '_blank',
relativePath: false,
toc: {
scope: '.markdown-section',
headings: 'h1, h2, h3, h4, h5, h6',
title: 'Table of Contents',
},
copyCode: {
buttonText: 'Copy to clipboard',
errorText: 'Error',
successText: 'Copied'
},
plugins: [
]
};
</script>
<!-- plugins -->
<script src="https://cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/docsify-sidebar-collapse.min.js" integrity="sha384-lMHOyuqf3B/T/BgfYxUKprN0bdRf8KhVTE11w76Tvtze86XHVSDYzxqNGDGgIi9I" crossorigin="anonymous"></script>
<!-- Docsify v4 -->
<script src="https://cdn.jsdelivr.net/npm/docsify@4/lib/docsify.min.js" integrity="sha384-KaHhgnx/OTLoJ4J33SSJsF4x1pk4I7q3s5ZOfIDHJYl6IG7Oyn2vNDsHiWJe46fD" crossorigin="anonymous"></script>
<!-- docsify-themeable -->
<script src="https://cdn.jsdelivr.net/npm/docsify-themeable@0/dist/js/docsify-themeable.min.js" integrity="sha384-ibjVZCUwWPrRrNc9BNkbbJvtYmTh8GYDNQgj+2jQVNDudOFgSQWs+Es6JhdoTIvf" crossorigin="anonymous"></script>
<!-- KaTeX -->
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/katex.min.js" integrity="sha384-G0zcxDFp5LWZtDuRMnBkk3EphCK1lhEf4UEyEM693ka574TZGwo4IWwS6QLzM/2t" crossorigin="anonymous"></script>
<!-- docsify-katex plugin -->
<script src="https://cdn.jsdelivr.net/npm/docsify-sidebar-collapse/dist/docsify-sidebar-collapse.min.js" integrity="sha384-lMHOyuqf3B/T/BgfYxUKprN0bdRf8KhVTE11w76Tvtze86XHVSDYzxqNGDGgIi9I" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/docsify/lib/plugins/search.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/docsify-copy-code/dist/docsify-copy-code.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/docsify-pagination/dist/docsify-pagination.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/docsify/lib/plugins/zoom-image.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/docsify-tabs/dist/docsify-tabs.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/docsify-katex@1.4.3/dist/docsify-katex.js" integrity="sha384-M76M/x5vGyeoej1covQQifl7T945mY+qgzNVrM/urHMCYjP8tnMsx5WCdeLZ74UE" crossorigin="anonymous"></script>
</body>
</html>
</html>
+52 -56
View File
@@ -4,50 +4,67 @@
✔️= Validation tests passed<br>
❌= 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||
|<br>||||
|**STATISTICS, ERRORS AND NUMERICAL ANALYSIS**|**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|`Atr`|GetAtr|Atr||
|ATRP - Average True Range Percent|||||
|ATRSTOP - ATR Trailing Stop ||GetAtrStop|||
|BBANDS - Bollinger Bands®||BollingerBands|||
|CHAND - Chandelier Exit||GetChandelier|||
|CRSI - Connor RSI||GetConnorsRsi|||
|CVI - Chaikins Volatility|||||
|DON - Donchian Channels||GetDonchian|||
|FCB - Fractal Chaos Bands||GetFcb|||
|FISHER - Fisher Transform|||||
|HV - Historical Volatility|||||
|ICH - Ichimoku Cloud||GetIchimoku|||
|KEL - Keltner Channels||GetKeltner|||
|NATR - Normalized Average True Range||GetAtr|||
|CHN - Price Channel Indicator|||||
|RSI - Relative Strength Index|`Rsi`|GetRsi|||
|SAR - Parabolic Stop and Reverse||GetParabolicSar|||
|SRSI - Stochastic RSI||GetStochRsi|||
|STARC - Starc Bands||GetStarcBands|||
|TR - True Range|||||
|UI - Ulcer Index||GetUlcerIndex|||
|VSTOP - Volatility Stop||GetVolatilityStop|||
|**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|||||
|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`||||
|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`||||
|<br>|||||
|**AVERAGES & TRENDS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady|
|**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`|`⭐`|`⭐`|`⭐`||
@@ -67,7 +84,6 @@
|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`||||
@@ -80,7 +96,6 @@
|SMMA - Smoothed Moving Average|`Smma`|`✔️`|||
|SSF - Ehler's Super Smoother Filter|||||
|SUPERTREND - Supertrend||`✔️`|||
|SWMA - Symmetric Weighted Moving Average|||||
|T3 - Tillson T3 Moving Average|`T3`|`✔️`|`✔️`||
|TEMA - Triple EMA Average|`Tema`|`✔️`|`✔️`|`✔️`|
|TRIMA - Triangular Moving Average|`Trima`|`✔️`||`✔️`|
@@ -89,34 +104,8 @@
|VORTEX - Vortex Indicator||`✔️`|||
|WMA - Weighted Moving Average|`Wma`|`✔️`||`✔️`|
|ZLEMA - Zero Lag EMA Average|`Zlema`|||`✔️`|
|<br>||||
|**VOLATILITY INDICATORS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady|
|ADL - Chaikin Accumulation Distribution Line||GetAdl|Ad||
|ADOSC - Chaikin Accumulation Distribution Oscillator||GetChaikinOsc|AdOsc||
|ATR - Average True Range||GetAtr|Atr||
|ATRP - Average True Range Percent|||||
|ATRSTOP - ATR Trailing Stop ||GetAtrStop|||
|BBANDS - Bollinger Bands®||BollingerBands|||
|CHAND - Chandelier Exit||GetChandelier|||
|CRSI - Connor RSI||GetConnorsRsi|||
|CVI - Chaikins Volatility|||||
|DON - Donchian Channels||GetDonchian|||
|FCB - Fractal Chaos Bands||GetFcb|||
|FISHER - Fisher Transform|||||
|HV - Historical Volatility|||||
|ICH - Ichimoku Cloud||GetIchimoku|||
|KEL - Keltner Channels||GetKeltner|||
|NATR - Normalized Average True Range||GetAtr|||
|CHN - Price Channel Indicator|||||
|RSI - Relative Strength Index||GetRsi|||
|SAR - Parabolic Stop and Reverse||GetParabolicSar|||
|SRSI - Stochastic RSI||GetStochRsi|||
|STARC - Starc Bands||GetStarcBands|||
|TR - True Range|||||
|UI - Ulcer Index||GetUlcerIndex|||
|VSTOP - Volatility Stop||GetVolatilityStop|||
|<br>||||
|**MOMENTUM INDICATORS & OSCILLATORS**|**QuanTALib**|Skender.Stock|TALib.NETCore|Tulip.NETCore|Trady|
|**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||
@@ -139,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|||||
@@ -156,8 +146,7 @@
|UO - Ultimate Oscillator||GetUltimate|||
|WILLR - Larry Williams' %R||GetWilliamsR|||
|WGAT - Williams Alligator||GetAlligator|||
|<br>||||
|**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|||||
@@ -171,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|
+1617
View File
File diff suppressed because it is too large Load Diff
+58 -6
View File
@@ -2,10 +2,11 @@ namespace QuanTAlib;
/// <summary>
/// EMA: Exponential Moving Average
/// EMA needs very short history buffer and calculates the EMA value using just the
/// previous EMA value. The weight of the new datapoint (alpha) is alpha = 2 / (period + 1)
/// </summary>
/// <remarks>
/// EMA needs very short history buffer and calculates the EMA value using just the
/// previous EMA value. The weight of the new datapoint (alpha) is alpha = 2 / (period + 1)
///
/// Key characteristics:
/// - Uses no buffer, relying only on the previous EMA value.
/// - The weight of new data points is calculated as alpha = 2 / (period + 1).
@@ -19,19 +20,52 @@ namespace QuanTAlib;
/// - https://www.investopedia.com/ask/answers/122314/what-exponential-moving-average-ema-formula-and-how-ema-calculated.asp
/// - https://blog.fugue88.ws/archives/2017-01/The-correct-way-to-start-an-Exponential-Moving-Average-EMA
/// </remarks>
public class Ema : AbstractBase
{
// inherited _index
// inherited _value
/// <summary>
/// The period for the EMA calculation.
/// </summary>
private readonly int _period;
/// <summary>
/// Circular buffer for SMA calculation.
/// </summary>
private CircularBuffer _sma;
/// <summary>
/// The last calculated EMA value.
/// </summary>
private double _lastEma, _p_lastEma;
/// <summary>
/// Compensator for early EMA values.
/// </summary>
private double _e, _p_e;
/// <summary>
/// The smoothing factor for EMA calculation.
/// </summary>
private readonly double _k;
/// <summary>
/// Flags to track initialization status.
/// </summary>
private bool _isInit, _p_isInit;
/// <summary>
/// Flag to determine whether to use SMA for initial values.
/// </summary>
private readonly bool _useSma;
/// <summary>
/// Initializes a new instance of the Ema class with a specified period.
/// </summary>
/// <param name="period">The period for EMA calculation.</param>
/// <param name="useSma">Whether to use SMA for initial values. Default is true.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
public Ema(int period, bool useSma = true)
{
if (period < 1)
@@ -47,23 +81,36 @@ public class Ema : AbstractBase
Init();
}
/// <summary>
/// Initializes a new instance of the Ema class with a specified alpha value.
/// </summary>
/// <param name="alpha">The smoothing factor for EMA calculation.</param>
public Ema(double alpha)
{
_k = alpha;
_useSma = false;
_sma = new(1);
Name = "Ema";
_period = 1;
WarmupPeriod = (int)Math.Ceiling(Math.Log(0.05) / Math.Log(1 - _k)); //95th percentile
Init();
}
/// <summary>
/// Initializes a new instance of the Ema class with a specified source and period.
/// </summary>
/// <param name="source">The source object for event subscription.</param>
/// <param name="period">The period for EMA calculation.</param>
/// <param name="useSma">Whether to use SMA for initial values. Default is true.</param>
public Ema(object source, int period, bool useSma = true) : this(period, useSma)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
//inhereted public void Sub(object source, in ValueEventArgs args)
/// <summary>
/// Initializes the Ema instance.
/// </summary>
public override void Init()
{
base.Init();
@@ -74,6 +121,10 @@ public class Ema : AbstractBase
_sma = new(_period);
}
/// <summary>
/// Manages the state of the Ema instance.
/// </summary>
/// <param name="isNew">Indicates whether the input is new.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
@@ -92,8 +143,9 @@ public class Ema : AbstractBase
}
/// <summary>
/// Core EMA calculation
/// Performs the EMA calculation.
/// </summary>
/// <returns>The calculated EMA value.</returns>
protected override double Calculation()
{
double result, _ema;
@@ -118,7 +170,7 @@ public class Ema : AbstractBase
_ema = _k * (Input.Value - _lastEma) + _lastEma;
// _useSma decides if we use compensator or not
result = (_useSma || _e == 0) ? _ema : _ema / (1 - _e);
result = (_useSma || _e <= double.Epsilon) ? _ema : _ema / (1 - _e);
}
_lastEma = _ema;
IsHot = _index >= WarmupPeriod;
+91 -64
View File
@@ -1,68 +1,93 @@
/// <summary>
/// Represents a Jurik Moving Average, based on known and reverse-engineered insights
/// </summary>
namespace QuanTAlib;
//TODO fails consistency test
public class Jma : AbstractBase
{
public readonly int Period;
private readonly double _period;
private readonly double _phase;
private readonly int _vshort, _vlong;
private readonly CircularBuffer _values;
private readonly CircularBuffer _voltyShort;
private readonly CircularBuffer _vsumBuff;
private readonly CircularBuffer _avoltyBuff;
private double _beta, _len1, _pow1;
private double _upperBand, _lowerBand, _prevMa1, _prevDet0, _prevDet1, _prevJma;
private double _p_UpperBand, _p_LowerBand, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma;
private double _len1;
private double _pow1;
private readonly double _beta;
private double _upperBand, _lowerBand, _p_upperBand, _p_lowerBand;
private double _prevMa1, _prevDet0, _prevDet1, _prevJma, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma;
private double _vSum, _p_vSum;
public Jma(int period, double phase = 0, int vshort = 10)
public double UpperBand { get; set; }
public double LowerBand { get; set; }
public double Volty { get; set; }
public double Factor { get; set; }
/// <summary>
/// Initializes a new instance of the Jma class with the specified parameters.
/// </summary>
/// <param name="period">The period over which to calculate the Jvolty.</param>
/// <param name="phase">The phase parameter for the JMA-style calculation.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Jma(int period, int phase = 0, double factor = 0.45, int buffer = 10)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
Period = period;
_vshort = vshort;
_vlong = 65;
Factor = factor;
_period = period;
_phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5);
_values = new CircularBuffer(period);
_voltyShort = new CircularBuffer(vshort);
_vsumBuff = new CircularBuffer(_vlong);
_avoltyBuff = new CircularBuffer(2);
_vsumBuff = new CircularBuffer(buffer);
_avoltyBuff = new CircularBuffer(65);
_beta = factor * (_period - 1) / (factor * (_period - 1) + 2);
Name = "JMA";
WarmupPeriod = period * 2;
Init();
Name = $"JMA({period})";
}
public Jma(object source, int period, double phase = 0, int vshort = 10) : this(period, phase, vshort)
/// <summary>
/// Initializes a new instance of the Jvolty class with the specified source and parameters.
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Jvolty.</param>
/// <param name="phase">The phase parameter for the JMA-style calculation.</param>
public Jma(object source, int period, int phase = 0, double factor = 0.45, int buffer = 10) : this(period, phase, factor, buffer)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Jma instance by setting up the initial state.
/// </summary>
public override void Init()
{
_upperBand = _lowerBand = _prevMa1 = _prevDet0 = _prevDet1 = _prevJma = 0.0;
_p_UpperBand = _p_LowerBand = _p_prevMa1 = _p_prevDet0 = _p_prevDet1 = _p_prevJma = 0.0;
_beta = 0.45 * (Period - 1) / (0.45 * (Period - 1) + 2);
_len1 = Math.Max((Math.Log(Math.Sqrt(Period - 1)) / Math.Log(2.0)) + 2.0, 0);
base.Init();
_upperBand = _lowerBand = 0.0;
_p_upperBand = _p_lowerBand = 0.0;
_len1 = Math.Max((Math.Log(Math.Sqrt(_period - 1)) / Math.Log(2.0)) + 2.0, 0);
_pow1 = Math.Max(_len1 - 2.0, 0.5);
_avoltyBuff.Clear();
_avoltyBuff.Add(0, true);
_avoltyBuff.Add(0, true);
base.Init();
_vsumBuff.Clear();
}
/// <summary>
/// Manages the state of the Jma instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
// Save current state
_p_UpperBand = _upperBand;
_p_LowerBand = _lowerBand;
_p_upperBand = _upperBand;
_p_lowerBand = _lowerBand;
_p_vSum = _vSum;
_p_prevMa1 = _prevMa1;
_p_prevDet0 = _prevDet0;
_p_prevDet1 = _prevDet1;
@@ -70,67 +95,69 @@ public class Jma : AbstractBase
}
else
{
// Restore previous state
_upperBand = _p_UpperBand;
_lowerBand = _p_LowerBand;
_upperBand = _p_upperBand;
_lowerBand = _p_lowerBand;
_vSum = _p_vSum;
_prevMa1 = _p_prevMa1;
_prevDet0 = _p_prevDet0;
_prevDet1 = _p_prevDet1;
_prevJma = _p_prevJma;
}
}
/// <summary>
/// Performs the Jma calculation for the current value.
/// </summary>
/// <returns>
/// The calculated Jma value for the current input.
/// </returns>
protected override double Calculation()
{
ManageState(Input.IsNew);
_values.Add(Input.Value, Input.IsNew);
if (_index == 1)
double price = Input.Value;
if (_index <= 1)
{
_prevMa1 = _prevJma = Input.Value;
return Input.Value;
_upperBand = _lowerBand = price;
_prevMa1 = _prevJma = price;
}
double hprice = _values.Max();
double lprice = _values.Min();
double del1 = hprice - _upperBand;
double del2 = lprice - _lowerBand;
double del1 = price - _upperBand;
double del2 = price - _lowerBand;
double volty = Math.Max(Math.Abs(del1), Math.Abs(del2));
_voltyShort.Add(volty, Input.IsNew);
double vsum = _vsumBuff.Newest() + 0.1 * (volty - _voltyShort.Oldest());
_vsumBuff.Add(vsum, Input.IsNew);
_vsumBuff.Add(volty, Input.IsNew);
_vSum += (_vsumBuff[^1] - _vsumBuff[0]) / _vsumBuff.Count;
_avoltyBuff.Add(_vSum, Input.IsNew);
double avgvolty = _avoltyBuff.Average();
double prevAvolty = _avoltyBuff.Newest();
double avolty = prevAvolty + 2.0 / (Math.Max(4.0 * Period, 30) + 1.0) * (vsum - prevAvolty);
_avoltyBuff.Add(avolty, Input.IsNew);
double rvolty = (avgvolty > 0) ? volty / avgvolty : 1;
rvolty = Math.Min(Math.Max(rvolty, 1.0), Math.Pow(_len1, 1.0 / _pow1));
double dVolty = (avolty > 0) ? volty / avolty : 0;
dVolty = Math.Min(Math.Max(dVolty, 1.0), Math.Pow(_len1, 1.0 / _pow1));
double pow2 = Math.Pow(rvolty, _pow1);
double Kv = Math.Pow(_beta, Math.Sqrt(pow2));
double pow2 = Math.Pow(dVolty, _pow1);
double len2 = Math.Sqrt(0.5 * (Period - 1)) * _len1;
double _Kv = Math.Pow(len2 / (len2 + 1), Math.Sqrt(pow2));
_upperBand = (del1 >= 0) ? price : price - (Kv * del1);
_lowerBand = (del2 <= 0) ? price : price - (Kv * del2);
_upperBand = (del1 > 0) ? hprice : hprice - (_Kv * del1);
_lowerBand = (del2 < 0) ? lprice : lprice - (_Kv * del2);
double alpha = Math.Pow(_beta, pow2);
double ma1 = (1 - alpha) * Input.Value + alpha * _prevMa1;
double _alpha = Math.Pow(_beta, pow2);
double ma1 = Input.Value + _alpha * (_prevMa1 - Input.Value); //original: (1 - _alpha) * Input.Value + _alpha * _prevMa1;
_prevMa1 = ma1;
double det0 = (1 - _beta) * (Input.Value - ma1) + _beta * _prevDet0;
double det0 = price + _beta * (_prevDet0 - price + ma1) - ma1; //original: (price - ma1) * (1 - _beta) + _beta * _prevDet0;
_prevDet0 = det0;
double ma2 = ma1 + (_phase + 1) * det0;
double ma2 = ma1 + _phase * det0;
double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - _prevJma)) + (alpha * alpha * _prevDet1);
double det1 = ((ma2 - _prevJma) * (1 - _alpha) * (1 - _alpha)) + (_alpha * _alpha * _prevDet1);
_prevDet1 = det1;
double jma = _prevJma + det1;
_prevJma = jma;
UpperBand = _upperBand;
LowerBand = _lowerBand;
Volty = volty;
IsHot = _index >= WarmupPeriod;
return jma;
}
}
}
+101 -33
View File
@@ -1,18 +1,18 @@
using System;
namespace QuanTAlib;
/// <summary>
/// RMA: Relative Moving Average (also known as Wilder's Moving Average)
/// RMA is similar to EMA but uses a different smoothing factor.
/// </summary>
/// <remarks>
/// RMA is similar to EMA but uses a different smoothing factor.
///
/// Key characteristics:
/// - Uses no buffer, relying only on the previous RMA value.
/// - The weight of new data points (alpha) is calculated as 1 / period.
/// - Provides a smoother curve compared to SMA and EMA, reacting more slowly to price changes.
///
/// Calculation method:
/// RMA = (Previous RMA * (period - 1) + New Data) / period
/// This implementation can use SMA for the first Period bars as a seeding value for RMA when useSma is true.
///
/// Sources:
/// - https://www.tradingview.com/pine-script-reference/v5/#fun_ta{dot}rma
@@ -20,75 +20,143 @@ namespace QuanTAlib;
/// </remarks>
public class Rma : AbstractBase
{
private readonly int _period;
private double _lastRma;
private readonly double _alpha;
private double _savedLastRma;
// inherited _index
// inherited _value
public Rma(int period)
/// <summary>
/// The period for the RMA calculation.
/// </summary>
private readonly int _period;
/// <summary>
/// Circular buffer for SMA calculation.
/// </summary>
private CircularBuffer _sma;
/// <summary>
/// The last calculated RMA value.
/// </summary>
private double _lastRma, _p_lastRma;
/// <summary>
/// Compensator for early RMA values.
/// </summary>
private double _e, _p_e;
/// <summary>
/// The smoothing factor for RMA calculation.
/// </summary>
private readonly double _k;
/// <summary>
/// Flags to track initialization status.
/// </summary>
private bool _isInit, _p_isInit;
/// <summary>
/// Flag to determine whether to use SMA for initial values.
/// </summary>
private readonly bool _useSma;
/// <summary>
/// Initializes a new instance of the Rma class with a specified period.
/// </summary>
/// <param name="period">The period for RMA calculation.</param>
/// <param name="useSma">Whether to use SMA for initial values. Default is true.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when period is less than 1.</exception>
public Rma(int period, bool useSma = true)
{
if (period < 1)
{
throw new ArgumentException("Period must be greater than or equal to 1.", nameof(period));
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
_period = period;
WarmupPeriod = period * 2;
_alpha = 1.0 / _period; // Wilder's smoothing factor
Name = $"Rma({_period})";
_k = 1.0 / _period; // Wilder's smoothing factor
_useSma = useSma;
_sma = new(period);
Name = "Rma";
WarmupPeriod = _period * 2; // RMA typically needs more warmup periods
Init();
}
public Rma(object source, int period) : this(period)
/// <summary>
/// Initializes a new instance of the Rma class with a specified source and period.
/// </summary>
/// <param name="source">The source object for event subscription.</param>
/// <param name="period">The period for RMA calculation.</param>
/// <param name="useSma">Whether to use SMA for initial values. Default is true.</param>
public Rma(object source, int period, bool useSma = true) : this(period, useSma)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
/// <summary>
/// Initializes the Rma instance.
/// </summary>
public override void Init()
{
base.Init();
_e = 1.0;
_lastRma = 0;
_savedLastRma = 0;
_isInit = false;
_p_isInit = false;
_sma = new(_period);
}
/// <summary>
/// Manages the state of the Rma instance.
/// </summary>
/// <param name="isNew">Indicates whether the input is new.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_savedLastRma = _lastRma;
_lastValidValue = Input.Value;
_p_lastRma = _lastRma;
_p_isInit = _isInit;
_p_e = _e;
_index++;
}
else
{
_lastRma = _savedLastRma;
_lastRma = _p_lastRma;
_isInit = _p_isInit;
_e = _p_e;
}
}
/// <summary>
/// Performs the RMA calculation.
/// </summary>
/// <returns>The calculated RMA value.</returns>
protected override double Calculation()
{
double result, _rma;
ManageState(Input.IsNew);
double rma;
if (_index == 1)
// when _UseSma == true, use SMA calculation until we have enough data points
if (!_isInit && _useSma)
{
rma = Input.Value;
}
else if (_index <= _period)
{
// Simple average during initial period
rma = (_lastRma * (_index - 1) + Input.Value) / _index;
_sma.Add(Input.Value, Input.IsNew);
_rma = _sma.Average();
result = _rma;
if (_index >= _period)
{
_isInit = true;
}
}
else
{
// Wilder's smoothing method
rma = _alpha * (_lastRma - Input.Value) + _lastRma;
// compensator for early rma values
_e = (_e > 1e-10) ? (1 - _k) * _e : 0;
_rma = _k * Input.Value + (1 - _k) * _lastRma;
// _useSma decides if we use compensator or not
result = (_useSma || _e <= double.Epsilon) ? _rma : _rma / (1 - _e);
}
_lastRma = rma;
_lastRma = _rma;
IsHot = _index >= WarmupPeriod;
return rma;
return result;
}
}
+6
View File
@@ -57,6 +57,12 @@ public abstract class AbstractBase : ITValue
Input2 = new(Time: Input.Time, Value: double.NaN, IsNew: Input.IsNew, IsHot: Input.IsHot);
return Process(input.Value, input.Time, input.IsNew);
}
public virtual TValue Calc(double value, bool IsNew)
{
Input = new(this.Time, Value: value, IsNew: IsNew, IsHot: false);
Input2 = new(this.Time, double.NaN, false, false);
return Process(Input.Value, Input.Time, Input.IsNew);
}
public virtual TValue Calc(TBar barInput)
{
+2
View File
@@ -32,6 +32,8 @@ public TBar() : this(DateTime.UtcNow, 0, 0, 0, 0, 0) { }
public TBar(double Open, double High, double Low, double Close, double Volume, bool IsNew = true) : this(DateTime.UtcNow, Open, High, Low, Close, Volume, IsNew) { }
public TBar(double value) : this(Time: DateTime.UtcNow, Open: value, High: value, Low: value, Close: value, Volume: value, IsNew: true) { }
public TBar(TValue value) : this(Time: value.Time, Open: value.Value, High: value.Value, Low: value.Value, Close: value.Value, Volume: value.Value, IsNew: value.IsNew) { }
public TBar(TBar v) : this(Time: v.Time, Open: v.Open, High: v.High, Low: v.Low, Close: v.Close, Volume: v.Volume, IsNew: true) { }
public static implicit operator double(TBar bar) => bar.Close;
public static implicit operator DateTime(TBar tv) => tv.Time;
+2 -2
View File
@@ -52,13 +52,13 @@ public class TSeries : List<TValue>
var pubEvent = source.GetType().GetEvent("Pub");
if (pubEvent != null)
{
/*
var nameProperty = source.GetType().GetProperty("Name");
if (nameProperty != null)
{
Name = nameProperty.GetValue(nameProperty)?.ToString()!;
}
*/
pubEvent.AddEventHandler(source, new ValueSignal(Sub));
}
}
+19 -19
View File
@@ -6,11 +6,11 @@ public class GbmFeed : TBarSeries
{
private readonly double _mu, _sigma;
private readonly RandomNumberGenerator _rng;
private double _lastClose, _lastHigh, _lastLow;
private double _lastClose;
public GbmFeed(double initialPrice = 100.0, double mu = 0.05, double sigma = 0.2)
{
_lastClose = _lastHigh = _lastLow = initialPrice;
_lastClose = initialPrice;
_mu = mu;
_sigma = sigma;
_rng = RandomNumberGenerator.Create();
@@ -24,9 +24,7 @@ public class GbmFeed : TBarSeries
DateTime startTime = DateTime.UtcNow - TimeSpan.FromHours(count);
for (int i = 0; i < count; i++)
{
Add(startTime, true);
Add(startTime, false);
Add(startTime, false);
Add(startTime, isNew: true);
startTime = startTime.AddHours(1);
}
}
@@ -36,27 +34,29 @@ public class GbmFeed : TBarSeries
double dt = 1.0 / 252;
double drift = (_mu - 0.5 * _sigma * _sigma) * dt;
double diffusion = _sigma * Math.Sqrt(dt) * GenerateNormalRandom();
double newClose = _lastClose * Math.Exp(drift + diffusion);
double open = _lastClose;
double high = Math.Max(_lastHigh, Math.Max(open, newClose) * (1 + GenerateRandomDouble() * 0.01));
double low = Math.Min(_lastLow, Math.Min(open, newClose) * (1 - GenerateRandomDouble() * 0.01));
double close = open * Math.Exp(drift + diffusion);
// Generate intra-bar price movements
double maxMove = Math.Abs(close - open) * 1.5; // Allow for some extra movement within the bar
double high = Math.Max(open, close) + maxMove * GenerateRandomDouble();
double low = Math.Min(open, close) - maxMove * GenerateRandomDouble();
// Ensure high is always greater than or equal to both open and close
high = Math.Max(high, Math.Max(open, close));
// Ensure low is always less than or equal to both open and close
low = Math.Min(low, Math.Min(open, close));
double volume = 1000 + GenerateRandomDouble() * 1000;
if (isNew)
{
_lastClose = newClose;
_lastClose = close;
}
else
{
high = Math.Max(_lastHigh, high);
low = Math.Min(_lastLow, low);
}
_lastHigh = high;
_lastLow = low;
TBar bar = new(time, open, high, low, newClose, volume, isNew);
return bar;
return new TBar(time, open, high, low, close, volume, isNew);
}
private double GenerateNormalRandom()
@@ -73,4 +73,4 @@ public class GbmFeed : TBarSeries
_rng.GetBytes(bytes);
return (double)BitConverter.ToUInt64(bytes, 0) / ulong.MaxValue;
}
}
}
+1
View File
@@ -31,6 +31,7 @@
<PackageIconUrl>https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png</PackageIconUrl>
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
<EnableDefaultCompileItems>false</EnableDefaultCompileItems>
<NoWarn>$(NoWarn);NU1903;NU5104</NoWarn>
</PropertyGroup>
<ItemGroup>
+21 -16
View File
@@ -4,13 +4,14 @@ namespace QuanTAlib;
/// Represents an Average True Range (ATR) calculator, a measure of market volatility.
/// </summary>
/// <remarks>
/// The ATR class calculates the average true range using an Exponential Moving Average (EMA)
/// The ATR class calculates the average true range using a Relative Moving Average (RMA)
/// of the true range. The true range is the greatest of: current high - current low,
/// absolute value of current high - previous close, or absolute value of current low - previous close.
/// </remarks>
public class Atr : AbstractBase
{
private readonly Ema _ma;
public double Tr { get; private set; }
private readonly Rma _ma;
private double _prevClose, _p_prevClose;
/// <summary>
@@ -26,7 +27,7 @@ public class Atr : AbstractBase
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
_ma = new(1.0 / period);
_ma = new(period, useSma: true);
WarmupPeriod = _ma.WarmupPeriod;
Name = $"ATR({period})";
}
@@ -50,6 +51,7 @@ public class Atr : AbstractBase
base.Init();
_ma.Init();
_prevClose = double.NaN;
Tr = 0;
}
/// <summary>
@@ -76,7 +78,7 @@ public class Atr : AbstractBase
/// The calculated ATR value for the current bar.
/// </returns>
/// <remarks>
/// This method calculates the true range for the current bar and then uses an EMA
/// This method calculates the true range for the current bar and then uses an RMA
/// to smooth the true range values. For the first bar, it uses the high-low range
/// as the true range.
/// </remarks>
@@ -84,22 +86,25 @@ public class Atr : AbstractBase
{
ManageState(BarInput.IsNew);
double trueRange = Math.Max(
Math.Max(
BarInput.High - BarInput.Low,
Math.Abs(BarInput.High - _prevClose)
),
Math.Abs(BarInput.Low - _prevClose)
);
if (_index < 2)
if (_index == 1)
{
trueRange = BarInput.High - BarInput.Low;
Tr = BarInput.High - BarInput.Low;
_prevClose = BarInput.Close;
}
else
{
Tr = Math.Max(
BarInput.High - BarInput.Low,
Math.Max(
Math.Abs(BarInput.High - _prevClose),
Math.Abs(BarInput.Low - _prevClose)
)
);
}
_ma.Calc(new TValue(Input.Time, Tr, BarInput.IsNew));
TValue emaTrueRange = _ma.Calc(new TValue(Input.Time, trueRange, Input.IsNew));
IsHot = _ma.IsHot;
_prevClose = BarInput.Close;
return emaTrueRange.Value;
return _ma.Value;
}
}
+73
View File
@@ -0,0 +1,73 @@
using System;
using System.Collections.Generic;
namespace QuanTAlib;
/// <summary>
/// Represents a Chande Momentum Oscillator (CMO) calculator.
/// </summary>
public class Cmo : AbstractBase
{
private readonly CircularBuffer _sumH;
private readonly CircularBuffer _sumL;
private double _prevValue, _p_prevValue;
public Cmo(int period)
{
if (period < 1)
throw new ArgumentOutOfRangeException(nameof(period));
_sumH = new(period);
_sumL = new(period);
WarmupPeriod = period+1;
Name = $"CMO({period})";
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_index++;
_p_prevValue = _prevValue;
}
else
{
_prevValue = _p_prevValue;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
if (_index == 0)
{
_prevValue = Input.Value;
}
double diff = Input.Value - _prevValue;
_prevValue = Input.Value;
if (diff > 0)
{
_sumH.Add(diff, Input.IsNew);
_sumL.Add(0, Input.IsNew);
}
else
{
_sumH.Add(0, Input.IsNew);
_sumL.Add(-diff, Input.IsNew);
}
// Calculate sums for the specified period only
double sumH = _sumH.Sum();
double sumL = _sumL.Sum();
double divisor = sumH + sumL;
return (Math.Abs(divisor) > double.Epsilon) ?
100.0 * ((sumH - sumL) / divisor) :
0.0;
}
}
+70 -38
View File
@@ -7,17 +7,25 @@ namespace QuanTAlib;
public class Jvolty : AbstractBase
{
private readonly int _period;
private readonly CircularBuffer _values;
private readonly CircularBuffer _voltyShort;
private readonly double _phase;
private readonly CircularBuffer _vsumBuff;
private readonly CircularBuffer _avoltyBuff;
private double _len1;
private double _pow1;
private double _upperBand;
private double _lowerBand;
private double _p_upperBand;
private double _p_lowerBand;
private readonly double _beta;
private double _upperBand, _lowerBand, _p_upperBand, _p_lowerBand;
private double _prevMa1, _prevDet0, _prevDet1, _prevJma, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma;
private double _vSum, _p_vSum;
public double UpperBand { get; set; }
public double LowerBand { get; set; }
public double Volty { get; set; }
public double VSum { get; set; }
public double Jma { get; set; }
public double AvgVolty { get; set; }
/// <summary>
/// Initializes a new instance of the Jvolty class with the specified parameters.
@@ -28,22 +36,21 @@ public class Jvolty : AbstractBase
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Jvolty(int period, int vshort = 10)
public Jvolty(int period, int phase = 0)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
_period = period;
int _vlong = 65;
_phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5);
_values = new CircularBuffer(period);
_voltyShort = new CircularBuffer(vshort);
_vsumBuff = new CircularBuffer(_vlong);
_avoltyBuff = new CircularBuffer(2);
_vsumBuff = new CircularBuffer(10);
_avoltyBuff = new CircularBuffer(65);
_beta = 0.45 * (period - 1) / (0.45 * (period - 1) + 2);
WarmupPeriod = period * 2;
Name = $"JVOLTY({period},{vshort})";
Name = $"JVOLTY({period})";
}
/// <summary>
@@ -53,7 +60,7 @@ public class Jvolty : AbstractBase
/// <param name="period">The period over which to calculate the Jvolty.</param>
/// <param name="phase">The phase parameter for the JMA-style calculation.</param>
/// <param name="vshort">The short-term volatility period.</param>
public Jvolty(object source, int period, int vshort = 10) : this(period, vshort)
public Jvolty(object source, int period, int phase = 0) : this(period, phase)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new BarSignal(Sub));
@@ -70,8 +77,7 @@ public class Jvolty : AbstractBase
_len1 = Math.Max((Math.Log(Math.Sqrt(_period - 1)) / Math.Log(2.0)) + 2.0, 0);
_pow1 = Math.Max(_len1 - 2.0, 0.5);
_avoltyBuff.Clear();
_avoltyBuff.Add(0, true);
_avoltyBuff.Add(0, true);
_vsumBuff.Clear();
}
/// <summary>
@@ -85,11 +91,21 @@ public class Jvolty : AbstractBase
_index++;
_p_upperBand = _upperBand;
_p_lowerBand = _lowerBand;
_p_vSum = _vSum;
_p_prevMa1 = _prevMa1;
_p_prevDet0 = _prevDet0;
_p_prevDet1 = _prevDet1;
_p_prevJma = _prevJma;
}
else
{
_upperBand = _p_upperBand;
_lowerBand = _p_lowerBand;
_vSum = _p_vSum;
_prevMa1 = _p_prevMa1;
_prevDet0 = _p_prevDet0;
_prevDet1 = _p_prevDet1;
_prevJma = _p_prevJma;
}
}
@@ -101,41 +117,57 @@ public class Jvolty : AbstractBase
/// </returns>
protected override double Calculation()
{
ManageState(BarInput.IsNew);
_values.Add(BarInput.Close, BarInput.IsNew);
ManageState(Input.IsNew);
double price = Input.Value;
if (_index == 1)
{
return 0;
_upperBand = _lowerBand = price;
}
double hprice = _values.Max();
double lprice = _values.Min();
double del1 = hprice - _upperBand;
double del2 = lprice - _lowerBand;
double del1 = price - _upperBand;
double del2 = price - _lowerBand;
double volty = Math.Max(Math.Abs(del1), Math.Abs(del2));
_voltyShort.Add(volty, BarInput.IsNew);
double vsum = _vsumBuff.Newest() + 0.1 * (volty - _voltyShort.Oldest());
_vsumBuff.Add(vsum, BarInput.IsNew);
_vsumBuff.Add(volty, Input.IsNew);
_vSum += (_vsumBuff[^1] - _vsumBuff[0]) / 10;
_avoltyBuff.Add(_vSum, Input.IsNew);
double avgvolty = _avoltyBuff.Average();
double prevAvolty = _avoltyBuff.Newest();
double avolty = prevAvolty + 2.0 / (Math.Max(4.0 * _period, 30) + 1.0) * (vsum - prevAvolty);
_avoltyBuff.Add(avolty, BarInput.IsNew);
double rvolty = (avgvolty > 0) ? volty / avgvolty : 1;
rvolty = Math.Min(Math.Max(rvolty, 1.0), Math.Pow(_len1, 1.0 / _pow1));
double dVolty = (avolty > 0) ? volty / avolty : 0;
dVolty = Math.Min(Math.Max(dVolty, 1.0), Math.Pow(_len1, 1.0 / _pow1));
double pow2 = Math.Pow(rvolty, _pow1);
double Kv = Math.Pow(_beta, Math.Sqrt(pow2));
double pow2 = Math.Pow(dVolty, _pow1);
double len2 = Math.Sqrt(0.5 * (_period - 1)) * _len1;
double Kv = Math.Pow(len2 / (len2 + 1), Math.Sqrt(pow2));
_upperBand = (del1 >= 0) ? price : price - (Kv * del1);
_lowerBand = (del2 <= 0) ? price : price - (Kv * del2);
_upperBand = (del1 > 0) ? hprice : hprice - (Kv * del1);
_lowerBand = (del2 < 0) ? lprice : lprice - (Kv * del2);
double alpha = Math.Pow(_beta, pow2);
double ma1 = (1 - alpha) * Input.Value + alpha * _prevMa1;
_prevMa1 = ma1;
double det0 = (price - ma1) * (1 - _beta) + _beta * _prevDet0;
_prevDet0 = det0;
double ma2 = ma1 + _phase * det0;
double det1 = ((ma2 - _prevJma) * (1 - alpha) * (1 - alpha) ) + (alpha * alpha * _prevDet1);
_prevDet1 = det1;
double jma = _prevJma + det1;
_prevJma = jma;
UpperBand = _upperBand;
LowerBand = _lowerBand;
Volty = volty;
VSum = _vSum;
AvgVolty = avgvolty;
Jma = jma;
IsHot = _index >= WarmupPeriod;
return volty;
}
}
+62
View File
@@ -0,0 +1,62 @@
using System;
namespace QuanTAlib;
/// <summary>
/// Represents a Relative Strength Index (RSI) calculator following Wilder's algorithm.
/// </summary>
public class Rsi : AbstractBase
{
private readonly Rma _avgGain;
private readonly Rma _avgLoss;
private double _prevValue, _p_prevValue;
public Rsi(int period = 14)
{
if (period < 1)
throw new ArgumentOutOfRangeException(nameof(period));
_avgGain = new(period, useSma: true);
_avgLoss = new(period, useSma: true);
_index = 0;
WarmupPeriod = period + 1;
Name = $"RSI({period})";
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_index++;
_p_prevValue = _prevValue;
}
else
{
_prevValue = _p_prevValue;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
if (_index == 1)
{
_prevValue = Input.Value;
}
double change = Input.Value - _prevValue;
double gain = Math.Max(change, 0);
double loss = Math.Max(-change, 0);
_prevValue = Input.Value;
_avgGain.Calc(gain, IsNew: Input.IsNew);
_avgLoss.Calc(loss, IsNew: Input.IsNew);
double rsi = (_avgLoss.Value > 0) ? 100 - (100 / (1 + (_avgGain.Value / _avgLoss.Value))) : 100;
return rsi;
}
}
+64
View File
@@ -0,0 +1,64 @@
using System;
namespace QuanTAlib;
/// <summary>
/// Jurik's superior replacement for RSI
/// </summary>
public class Rsx : AbstractBase
{
private readonly Rma _avgGain;
private readonly Rma _avgLoss;
private readonly Jma _rsx;
private double _prevValue, _p_prevValue;
public Rsx(int period = 14, int phase = 0, double factor = 0.55)
{
if (period < 1)
throw new ArgumentOutOfRangeException(nameof(period));
_avgGain = new(period);
_avgLoss = new(period);
_rsx = new(8, 100, 0.25, 3);
_index = 0;
WarmupPeriod = period + 1;
Name = $"RSX({period})";
}
protected override void ManageState(bool isNew)
{
if (isNew)
{
_index++;
_p_prevValue = _prevValue;
}
else
{
_prevValue = _p_prevValue;
}
}
protected override double Calculation()
{
ManageState(Input.IsNew);
if (_index == 1)
{
_prevValue = Input.Value;
}
double change = Input.Value - _prevValue;
double gain = Math.Max(change, 0);
double loss = Math.Max(-change, 0);
_prevValue = Input.Value;
_avgGain.Calc(gain, IsNew: Input.IsNew);
_avgLoss.Calc(loss, IsNew: Input.IsNew);
double rsi = (_avgLoss.Value > 0) ? 100 - (100 / (1 + (_avgGain.Value / _avgLoss.Value))) : 100;
double rsx = _rsx.Calc(rsi, Input.IsNew);
return rsx;
}
}
+6 -5
View File
@@ -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,14 +20,10 @@
- Volatility Cone
- Bollinger Bands
- Stochastic Volatility: Typically modeled using closing prices, but can incorporate other price information
## OHLC Input (Open, High, Low, Close)
- Garman-Klass Volatility
- Rogers-Satchell Volatility
- Yang-Zhang Volatility
- Parkinson Volatility (High, Low)
- Average True Range (ATR) (High, Low, Close)
- Chaikin Volatility (High, Low)
- Keltner Channels (typically Close, High, Low)
- High-Low Volatility (High, Low)
+42 -99
View File
@@ -4,7 +4,7 @@
#!csharp
#r "..\src\obj\Debug\QuanTAlib.dll"
#r "..\lib\obj\Debug\QuanTAlib.dll"
#r "nuget:Skender.Stock.Indicators"
using Skender.Stock.Indicators;
@@ -13,113 +13,56 @@ QuanTAlib.Formatters.Initialize();
#!csharp
Atr ma = new(10);
GbmFeed gbm = new();
EmaCalc ema1 = new(gbm.Close, 10, useSma: false);
EmaCalc ema2 = new(gbm.Close, 10, useSma: true);
TValSeries res1 = new(ema1);
TValSeries res2 = new(ema2);
gbm.Add(50);
List<double> mse1 = new();
List<double> mse2 = new();
gbm.Add(30);
IEnumerable<Quote> quotes = gbm.Select(item => new Quote { Date = item.Time, Open = (decimal)item.Open, High = (decimal)item.High, Low = (decimal)item.Low, Close = (decimal)item.Close, Volume = (decimal)item.Volume });
var SkResults = quotes.GetAtr(10).Select(i => i.Atr.Null2NaN()!);
for (int i=0; i< gbm.Length; i++) {
double v= gbm.Close[i].Value;
double e1 = res1[i].Value;
mse1.Add((e1-v)*(e1-v));
double e2 = res2[i].Value;
mse2.Add((e2-v)*(e2-v));
//Console.WriteLine($"{i,3} {mse1.Average(),10:F4} {mse2.Average(),10:F4}");
ma.Calc(gbm[i]);
Console.WriteLine($"{i,3} {ma.Value,10:F3} \t {SkResults.ElementAt(i):F3}");
}
Console.WriteLine($"{mse2.Average()-mse1.Average(),10:F8}");
#!csharp
display(res1);
#!csharp
Atr ma = new(10);
GbmFeed gbm = new();
EmaCalc ema1 = new(gbm.Close, 10, useSma: false);
EmaCalc ema2 = new(gbm.Close, 10, useSma: true);
TValSeries res1 = new(ema1);
TValSeries res2 = new(ema2);
gbm.Add(30);
IEnumerable<Quote> quotes = gbm.Select(item => new Quote { Date = item.Time, Open = (decimal)item.Open, High = (decimal)item.High, Low = (decimal)item.Low, Close = (decimal)item.Close, Volume = (decimal)item.Volume });
var SkResults = quotes.GetTr().Select(i => i.Tr.Null2NaN()!);
for (int i=0; i< gbm.Length; i++) {
ma.Calc(new TBar(gbm[i]));
Console.WriteLine($"{gbm.High[i].Value,6:F4} \t{gbm.Low[i].Value,6:F4} \t{gbm.Close[i].Value,6:F4} \t{ma.Tr,10:F4} \t{SkResults.ElementAt(i),10:F4}");
}
#!csharp
//ATR test
GbmFeed gbm = new();
TBarSeries feed = new(gbm);
Atr ma1 = new(gbm, 10);
TSeries res1 = new(ma1);
gbm.Add(30);
IEnumerable<Quote> quotes = gbm.Select(item => new Quote { Date = item.Time, Open = (decimal)item.Open, High = (decimal)item.High, Low = (decimal)item.Low, Close = (decimal)item.Close, Volume = (decimal)item.Volume });
var SkResults = quotes.GetAtr(10).Select(i => i.Atr.Null2NaN()!);
for (int i=0; i< gbm.Length; i++) {
double delta = Math.Round(res1[i].Value, 10) - Math.Round(SkResults.ElementAt(i), 10);
//Console.WriteLine($"{i,3} {gbm.High[i].Value,6:F2} {gbm.Low[i].Value,6:F2} {gbm.Close[i].Value,6:F2} {res1[i].Value,10:F4} {SkResults.ElementAt(i),10:F4}\t{delta}");
Console.WriteLine($"{i,3} h:{gbm.High[i].Value,6:F2} l:{gbm.Low[i].Value,6:F2} c:{gbm.Close[i].Value,6:F2} {res1[i].Atr,10:F4} {SkResults.ElementAt(i),10:F4}\t{delta}");
}
#!csharp
//EMA test
GbmFeed gbm = new();
Ema ema1 = new(gbm.Close, 10, useSma: true);
TSeries res1 = new(ema1);
gbm.Add(30);
IEnumerable<Quote> quotes = gbm.Close.Select(item => new Quote { Date = item.Time, Close = (decimal)item.Value });
var SkResults = quotes.GetEma(10).Select(i => i.Ema.Null2NaN()!);
for (int i=0; i< gbm.Length; i++) {
Console.WriteLine($"{i,3} {gbm.Close[i].Value,6:F2} {res1[i].Value,10:F4} {res2[i].Value,10:F4} {SkResults.ElementAt(i),10:F4}");
double delta = Math.Round(res1[i].Value, 10) - Math.Round(SkResults.ElementAt(i), 10);
Console.WriteLine($"{i,3} {gbm.Close[i].Value,6:F2} {res1[i].Value,10:F4} {SkResults.ElementAt(i),10:F4}\t{delta}");
}
#!csharp
TValSeries test = new();
EmaCalc ma1 = new(test, 7, true);
TValSeries res1 = new(ma1);
EmaCalc ma2 = new(test, 7, false);
TValSeries res2 = new(ma2);
test.Add(new[]{1.0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0});
for (int i=0; i<res1.Count; i++) {
Console.WriteLine($"{i,2} {test[i].Value,7:F4} {res1[i].Value,7:F4} {res2[i].Value,7:F4}");
}
#!csharp
TValSeries test = new();
EmaCalc ma = new(test,3);
TValSeries result = new();
for (int i=1; i<10; i++) {
test.Add(new TValue(DateTime.Now, (double)i, true, true));
result.Add(ma.Tick);
}
display(result);
#!csharp
TValSeries test = new();
SmaCalc ma = new(test,7);
TValSeries result = new(ma);
test.Add(new[]{81.59, 81.06, 82.87, 83.00, 83.61, 83.15, 82.84, 83.99, 84.55, 84.36, 85.53, 86.54, 86.89, 87.77, 87.29});
//test.Add(new[]{1.0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0});
display(result);
#!csharp
TValue test = new(DateTime.Today, 100, IsHot: false);
TValSeries pub = new();
TValSeries sub = new(pub);
pub.Add(test);
pub.Add(test);
pub.Add(2, true);
pub.Add(DateTime.Today, 123.1234214234, IsHot: true);
display(sub);
display(test);
#!csharp
TBar test = new(DateTime.Now, double.NaN,1,2,3,400.1234);
TBarSeries source = new();
TValSeries target = new(source.Close);
source.Add(new TBar(DateTime.Now,1,2,3,4,125, true));
source.Add(new TBar(DateTime.Now,2,1,5,2,1312, true));
source.Add(test);
source.Name = "MSFT";
display(source);
display(test)
#!csharp
#r "nuget:Skender.Stock.Indicators"
using Skender.Stock.Indicators;
+90 -69
View File
@@ -82,58 +82,77 @@ TSeries MarketJMA = new() { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
#!csharp
public class Jma1 : AbstractBase
public class Jmaxx : AbstractBase
{
public readonly int Period;
private readonly double _period;
private readonly double _phase;
private readonly int _vshort, _vlong;
private CircularBuffer _voltyShort;
private CircularBuffer _vsumBuff;
private CircularBuffer _avoltyBuff;
private readonly CircularBuffer _vsumBuff;
private readonly CircularBuffer _avoltyBuff;
private double _beta, _len1, _pow1;
private double _upperBand, _lowerBand, _prevMa1, _prevDet0, _prevDet1, _prevJma;
private double _p_UpperBand, _p_LowerBand, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma;
private double _len1;
private double _pow1;
private readonly double _beta;
private double _upperBand, _lowerBand, _p_upperBand, _p_lowerBand;
private double _prevMa1, _prevDet0, _prevDet1, _prevJma, _p_prevMa1, _p_prevDet0, _p_prevDet1, _p_prevJma;
private double _vSum, _p_vSum;
public Jma1(int period, double phase = 0, int vshort = 10) : base()
public double UpperBand { get; set; }
public double LowerBand { get; set; }
public double Volty { get; set; }
/// <summary>
/// Initializes a new instance of the Jma class with the specified parameters.
/// </summary>
/// <param name="period">The period over which to calculate the Jvolty.</param>
/// <param name="phase">The phase parameter for the JMA-style calculation.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Jmaxx(int period, int phase = 0)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
Period = period;
_vshort = vshort;
_vlong = 65;
_period = period;
_phase = Math.Clamp((phase * 0.01) + 1.5, 0.5, 2.5);
_voltyShort = new CircularBuffer(vshort);
_vsumBuff = new CircularBuffer(_vlong);
_avoltyBuff = new CircularBuffer(2);
_vsumBuff = new CircularBuffer(10);
_avoltyBuff = new CircularBuffer(65);
_beta = 0.45 * (_period - 1) / (0.45 * (_period - 1) + 2);
Name = "JMA";
WarmupPeriod = period * 2;
Init();
WarmupPeriod = (int)_period * 2;
Name = $"JMA({period})";
}
/// <summary>
/// Initializes the Jma instance by setting up the initial state.
/// </summary>
public override void Init()
{
_upperBand = _lowerBand = _prevMa1 = _prevDet0 = _prevDet1 = _prevJma = 0.0;
_p_UpperBand = _p_LowerBand = _p_prevMa1 = _p_prevDet0 = _p_prevDet1 = _p_prevJma = 0.0;
_avoltyBuff.Clear();
_avoltyBuff.Add(0, true);
_avoltyBuff.Add(0, true);
base.Init();
_upperBand = _lowerBand = 0.0;
_p_upperBand = _p_lowerBand = 0.0;
_len1 = Math.Max((Math.Log(Math.Sqrt(_period - 1)) / Math.Log(2.0)) + 2.0, 0);
_pow1 = Math.Max(_len1 - 2.0, 0.5);
_avoltyBuff.Clear();
_vsumBuff.Clear();
}
/// <summary>
/// Manages the state of the Jma instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
// Save current state
_p_UpperBand = _upperBand;
_p_LowerBand = _lowerBand;
_p_upperBand = _upperBand;
_p_lowerBand = _lowerBand;
_p_vSum = _vSum;
_p_prevMa1 = _prevMa1;
_p_prevDet0 = _prevDet0;
_p_prevDet1 = _prevDet1;
@@ -141,66 +160,73 @@ public class Jma1 : AbstractBase
}
else
{
// Restore previous state
_upperBand = _p_UpperBand;
_lowerBand = _p_LowerBand;
_upperBand = _p_upperBand;
_lowerBand = _p_lowerBand;
_vSum = _p_vSum;
_prevMa1 = _p_prevMa1;
_prevDet0 = _p_prevDet0;
_prevDet1 = _p_prevDet1;
_prevJma = _p_prevJma;
}
}
/// <summary>
/// Performs the Jma calculation for the current value.
/// </summary>
/// <returns>
/// The calculated Jma value for the current input.
/// </returns>
protected override double Calculation()
{
ManageState(Input.IsNew);
double price = Input.Value;
if (_index == 1)
{
_prevMa1 = _prevJma = Input.Value;
return Input.Value;
_upperBand = _lowerBand = price;
}
double del1 = Input.Value - _upperBand;
double del2 = Input.Value - _lowerBand;
double del1 = price - _upperBand;
double del2 = price - _lowerBand;
double volty = Math.Max(Math.Abs(del1), Math.Abs(del2));
_voltyShort.Add(volty, Input.IsNew);
double vsum = _vsumBuff.Newest() + 0.1 * (volty - _voltyShort.Oldest());
_vsumBuff.Add(vsum, Input.IsNew);
_vsumBuff.Add(volty, Input.IsNew);
_vSum += (_vsumBuff[^1] - _vsumBuff[0]) / 10;
_avoltyBuff.Add(_vSum, Input.IsNew);
double avgvolty = _avoltyBuff.Average();
double avolty = 0;
for (int i = 0; i < _vsumBuff.Count; i++) { avolty += _vsumBuff[i]; }
avolty /= _vsumBuff.Count;
double rvolty = (avgvolty > 0) ? volty / avgvolty : 1;
rvolty = Math.Min(Math.Max(rvolty, 1.0), Math.Pow(_len1, 1.0 / _pow1));
double rVolty = (avolty > 0) ? volty / avolty *20: 0;
double _len1 = Math.Max((Math.Log(Math.Sqrt(Period)) / Math.Log(2.0)) + 2.0, 0);
double _pow1 = Math.Max(_len1 - 2, 0.5);
double pow2 = Math.Pow(rvolty, _pow1);
double Kv = Math.Pow(_beta, Math.Sqrt(pow2));
rVolty = Math.Clamp(rVolty, 1.0, Math.Pow(_len1, 1.0 / _pow1));
_upperBand = (del1 >= 0) ? price : price - (Kv * del1);
_lowerBand = (del2 <= 0) ? price : price - (Kv * del2);
double _pow2 = Math.Pow(rVolty, _pow1);
double _beta = 0.45 * (Period - 1) / (0.45 * (Period - 1) + 2);
double len2 = Math.Sqrt(0.5 * (Period - 1)) * _len1;
double _Kv = Math.Pow (_beta, Math.Sqrt(_pow2)) *1.5;
_upperBand = (del1 > 0) ? Input.Value : Input.Value - (_Kv * del1);
_lowerBand = (del2 < 0) ? Input.Value : Input.Value - (_Kv * del2);
double alpha = Math.Pow(_beta, _pow2);
double ma1 = alpha * (_prevMa1 - Input.Value) + Input.Value;
double alpha = Math.Pow(_beta, pow2);
double ma1 = (1 - alpha) * Input.Value + alpha * _prevMa1;
_prevMa1 = ma1;
double det0 = _beta * (_prevDet0 - Input.Value + ma1) + Input.Value - ma1;
double det0 = (price - ma1) * (1 - _beta) + _beta * _prevDet0;
_prevDet0 = det0;
double ma2 = ma1 + _phase * det0;
double det1 = ((1 - alpha) * (1 - alpha) * (ma2 - _prevJma)) + (alpha * alpha * _prevDet1 );
double det1 = ((ma2 - _prevJma) * (1 - alpha) * (1 - alpha) ) + (alpha * alpha * _prevDet1);
_prevDet1 = det1;
double jma = _prevJma + det1;
_prevJma = jma;
UpperBand = _upperBand;
LowerBand = _lowerBand;
Volty = volty;
IsHot = _index >= WarmupPeriod;
return jma;
}
@@ -208,22 +234,17 @@ public class Jma1 : AbstractBase
#!csharp
TSeries ma = Triangle;
TSeries re = TriangleJMA;
TSeries ma = Complex;
TSeries re = ComplexJMA;
TSeries out1 = new();
TSeries out2 = new();
Jma calc = new(10);
Jma1 calc1 = new(10);
Jmaxx calc = new(10);
foreach (var value in ma) { out1.Add(calc.Calc(value)); }
foreach (var value in ma) { out2.Add(calc1.Calc(value)); }
Plot plt = new();
var sigplot = plt.Add.Signal(ma.v.ToArray()[60..80]);
var jmaplot = plt.Add.Signal(re.v.ToArray()[60..80]); sigplot.Color = ScottPlot.Colors.Red; sigplot.LineWidth = 2; jmaplot.LineWidth = 3;
//var jma1plot = plt.Add.Signal(out1.v.ToArray()[60..80]); jma1plot.Color = ScottPlot.Colors.Purple; jma1plot.LineWidth = 3;
var jma2plot = plt.Add.Signal(out2.v.ToArray()[60..80]); jma2plot.Color = ScottPlot.Colors.Blue; jma2plot.LineWidth = 3;
var jma1plot = plt.Add.Signal(out1.v.ToArray()[60..80]); jma1plot.Color = ScottPlot.Colors.Purple; jma1plot.LineWidth = 3;
plt.Display();
#!csharp
#r "nuget: Plotly.net.Interactive"
using Plotly.NET.Interactive;
+6 -3
View File
@@ -9,7 +9,10 @@ public class JmaIndicator : Indicator, IWatchlistIndicator
public int Periods { get; set; } = 10;
[InputParameter("Phase", sortIndex: 2, -100, 100, 1, 0)]
public double Phase { get; set; } = 0;
public int Phase { get; set; } = 0;
[InputParameter("Beta factor", sortIndex: 3, minimum: 0, maximum:5 , increment: 0.01, decimalPlaces: 2)]
public double Factor { get; set; } = 0.45;
[InputParameter("Data source", sortIndex: 4, variants: [
"Open", SourceType.Open,
@@ -34,7 +37,7 @@ public class JmaIndicator : Indicator, IWatchlistIndicator
public int MinHistoryDepths => Math.Max(65,Periods * 2);
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public override string ShortName => $"JMA {Periods}:{Phase}:{SourceName}";
public override string ShortName => $"JMA {Periods}:{Phase}:{Factor:F2}:{SourceName}";
public JmaIndicator()
{
@@ -49,7 +52,7 @@ public class JmaIndicator : Indicator, IWatchlistIndicator
protected override void OnInit()
{
ma = new Jma(Periods, Phase);
ma = new Jma(period: Periods, phase: Phase, factor: Factor);
SourceName = Source.ToString();
base.OnInit();
}
+149
View File
@@ -0,0 +1,149 @@
using System.Diagnostics.Metrics;
using System.Drawing;
using System.Drawing.Drawing2D;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class MacdIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Slow EMA", sortIndex: 1, 1, 1000, 1, 0)]
public int Slow { get; set; } = 26;
[InputParameter("Fast EMA", sortIndex: 2, 1, 2000, 1, 0)]
public int Fast { get; set; } = 12;
[InputParameter("Signal line", sortIndex: 3, 1, 2000, 1, 0)]
public int Signal { get; set; } = 9;
[InputParameter("Use SMA for warmup period", sortIndex: 2)]
public bool UseSMA { get; set; } = false;
[InputParameter("Data source", sortIndex: 3, variants: [
"Open", SourceType.Open,
"High", SourceType.High,
"Low", SourceType.Low,
"Close", SourceType.Close,
"HL/2 (Median)", SourceType.HL2,
"OC/2 (Midpoint)", SourceType.OC2,
"OHL/3 (Mean)", SourceType.OHL3,
"HLC/3 (Typical)", SourceType.HLC3,
"OHLC/4 (Average)", SourceType.OHLC4,
"HLCC/4 (Weighted)", SourceType.HLCC4
])]
public SourceType Source { get; set; } = SourceType.Close;
[InputParameter("Show cold values", sortIndex: 21)]
public bool ShowColdValues { get; set; } = true;
private Ema? slow_ma;
private Ema? fast_ma;
private Ema? signal_ma;
private Slope? histSlope;
protected LineSeries? MainSeries;
protected LineSeries? SignalSeries;
protected LineSeries? HistogramSeries;
protected LineSeries? HistSlopeSeries;
protected string? SourceName;
public int MinHistoryDepths => Slow;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public override string ShortName => $"MACD {Slow}:{Fast}:{Signal}";
public MacdIndicator()
{
OnBackGround = true;
SeparateWindow = true;
SourceName = Source.ToString();
Name = "MACD - Moving Average Convergence Divergence";
Description = "MACD";
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);
HistSlopeSeries.Visible = false;
AddLineSeries(MainSeries);
AddLineSeries(SignalSeries);
AddLineSeries(HistogramSeries);
AddLineSeries(HistSlopeSeries);
}
protected override void OnInit()
{
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();
}
protected override void OnUpdate(UpdateArgs args)
{
TValue input = this.GetInputValue(args, Source);
slow_ma!.Calc(input);
fast_ma!.Calc(input);
double main = fast_ma.Value - slow_ma.Value;
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);
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)
{
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]*2.0);
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);
base.OnPaintChart(args);
}
}
+75 -1
View File
@@ -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)
@@ -59,14 +65,35 @@ public static class IndicatorExtensions
#pragma warning disable CA1416 // Validate platform compatibility
public static void PaintHLine(this Indicator indicator, PaintChartEventArgs args, double value, Pen pen)
{
if (indicator.CurrentChart == null)
return;
Graphics gr = args.Graphics;
var mainWindow = indicator.CurrentChart.Windows[args.WindowIndex];
var converter = mainWindow.CoordinatesConverter;
var clientRect = mainWindow.ClientRectangle;
gr.SetClip(clientRect);
int leftX = clientRect.Left;
int rightX = clientRect.Right;
int Y = (int)converter.GetChartY(value);
using (pen)
{
gr.DrawLine(pen, new Point(leftX, Y), new Point(rightX, Y));
}
}
public static void PaintSmoothCurve(this Indicator indicator, PaintChartEventArgs args, LineSeries series, int warmupPeriod, bool showColdValues = true, double tension = 0.2)
{
if (!series.Visible || indicator.CurrentChart == null)
return;
Graphics gr = args.Graphics;
var mainWindow = indicator.CurrentChart.MainWindow;
gr.SmoothingMode = SmoothingMode.AntiAlias;
var mainWindow = indicator.CurrentChart.Windows[args.WindowIndex];
var converter = mainWindow.CoordinatesConverter;
var clientRect = mainWindow.ClientRectangle;
gr.SetClip(clientRect);
@@ -110,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)
+15 -2
View File
@@ -8,9 +8,12 @@ public class AtrIndicator : Indicator, IWatchlistIndicator
[InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
public int Periods { get; set; } = 20;
[InputParameter("Show cold values", sortIndex: 21)]
public bool ShowColdValues { get; set; } = true;
private Atr? atr;
protected LineSeries? AtrSeries;
public static int MinHistoryDepths => 2;
public int MinHistoryDepths => Math.Max(5, Periods * 2);
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public AtrIndicator()
@@ -19,7 +22,7 @@ public class AtrIndicator : Indicator, IWatchlistIndicator
Description = "Measures market volatility by calculating the average range between high and low prices.";
SeparateWindow = true;
AtrSeries = new("ATR", Color.Blue, 2, LineStyle.Solid);
AtrSeries = new($"ATR {Periods}", Color.Blue, 2, LineStyle.Solid);
AddLineSeries(AtrSeries);
}
@@ -35,7 +38,17 @@ public class AtrIndicator : Indicator, IWatchlistIndicator
TValue result = atr!.Calc(input);
AtrSeries!.SetValue(result.Value);
AtrSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here
}
#pragma warning disable CA1416 // Validate platform compatibility
public override string ShortName => $"ATR ({Periods})";
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
this.PaintHLine(args, 0.05, new Pen(Color.DarkRed, width: 2));
this.PaintSmoothCurve(args, AtrSeries!, atr!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2);
}
}
+72
View File
@@ -0,0 +1,72 @@
using System.Drawing;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class CmoIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
public int Periods { get; set; } = 9;
[InputParameter("Data source", sortIndex: 5, variants: [
"Open", SourceType.Open,
"High", SourceType.High,
"Low", SourceType.Low,
"Close", SourceType.Close,
"HL/2 (Median)", SourceType.HL2,
"OC/2 (Midpoint)", SourceType.OC2,
"OHL/3 (Mean)", SourceType.OHL3,
"HLC/3 (Typical)", SourceType.HLC3,
"OHLC/4 (Average)", SourceType.OHLC4,
"HLCC/4 (Weighted)", SourceType.HLCC4
])]
public SourceType Source { get; set; } = SourceType.Close;
[InputParameter("Show cold values", sortIndex: 21)]
public bool ShowColdValues { get; set; } = true;
private Cmo? cmo;
protected string? SourceName;
protected LineSeries? CmoSeries;
public int MinHistoryDepths => Periods + 1;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public CmoIndicator()
{
Name = "CMO - Chande Momentum Oscillator";
Description = "Measures the momentum of price changes using the difference between the sum of recent gains and the sum of recent losses.";
SeparateWindow = true;
SourceName = Source.ToString();
CmoSeries = new($"CMO {Periods}", Color.Blue, 2, LineStyle.Solid);
AddLineSeries(CmoSeries);
}
protected override void OnInit()
{
cmo = new Cmo(Periods);
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TValue input = this.GetInputValue(args, Source);
cmo!.Calc(input);
CmoSeries!.SetValue(cmo.Value);
CmoSeries!.SetMarker(0, Color.Transparent); //OnPaintChart draws the line, hidden here
}
public override string ShortName => $"CMO ({Periods}:{SourceName})";
#pragma warning disable CA1416 // Validate platform compatibility
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
this.PaintHLine(args, 0, new Pen(Color.DarkGray, 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);
}
}
+86
View File
@@ -0,0 +1,86 @@
using System.Drawing;
using System.Drawing.Drawing2D;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class FlowIndicator : Indicator, IWatchlistIndicator
{
protected string? SourceName;
public static int MinHistoryDepths => 2;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public FlowIndicator()
{
Name = "Flow Visualization";
SeparateWindow = false;
}
protected override void OnInit()
{
// placeholder
}
protected override void OnUpdate(UpdateArgs args)
{
// placeholder
}
#pragma warning disable CA1416 // Validate platform compatibility
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
Graphics gr = args.Graphics;
gr.SmoothingMode = System.Drawing.Drawing2D.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);
int width = this.CurrentChart.BarsWidth;
for (int i = rightIndex; i < leftIndex; i++)
{
int barX1 = (int)converter.GetChartX(this.HistoricalData.Time(i));
int barY1 = (int)converter.GetChartY(this.HistoricalData.Open(i));
int barYHigh = (int)converter.GetChartY(this.HistoricalData.High(i));
int barYLow = (int)converter.GetChartY(this.HistoricalData.Low(i));
int barX2 = barX1 + width;
int barY2 = (int)converter.GetChartY(this.HistoricalData.Close(i));
using (Brush transparentBrush = new SolidBrush(Color.FromArgb(250, 70, 70, 70)))
{
gr.FillRectangle(transparentBrush, barX1, barYHigh - 1, CurrentChart.BarsWidth, Math.Abs(barYLow - barYHigh) + 2);
}
using (Brush circ = new SolidBrush(Color.FromArgb(100, 255, 255, 0)))
{
int size = 3;
gr.FillEllipse(circ, barX1 - size, barY1 - size, 2 * size, 2 * size);
gr.FillEllipse(circ, barX2 - size, barY2 - size, 2 * size, 2 * size);
}
using (Pen defaultPen = new(Color.Yellow, 3))
{
defaultPen.StartCap = LineCap.Round;
defaultPen.EndCap = LineCap.Round;
gr.DrawLine(defaultPen, barX1, barY1, barX2, barY2);
}
if (i > 0)
{
int barX0 = (int)converter.GetChartX(this.HistoricalData.Time(i - 1));
int barY0 = (int)converter.GetChartY(this.HistoricalData.Open(i - 1));
using (Pen dottedPen = new(Color.Yellow, 1))
{
dottedPen.DashStyle = DashStyle.Dot;
gr.DrawLine(dottedPen, barX2, barY2, barX0, barY0);
}
}
}
}
}
+67
View File
@@ -0,0 +1,67 @@
using System.Drawing;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class JbandsIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
public int Periods { get; set; } = 14;
[InputParameter("Data source", sortIndex: 5, variants: [
"Open", SourceType.Open,
"High", SourceType.High,
"Low", SourceType.Low,
"Close", SourceType.Close,
"HL/2 (Median)", SourceType.HL2,
"OC/2 (Midpoint)", SourceType.OC2,
"OHL/3 (Mean)", SourceType.OHL3,
"HLC/3 (Typical)", SourceType.HLC3,
"OHLC/4 (Average)", SourceType.OHLC4,
"HLCC/4 (Weighted)", SourceType.HLCC4
])]
public SourceType Source { get; set; } = SourceType.Close;
[InputParameter("vShort", sortIndex: 6, -100, 100, 1, 0)]
public int Phase { get; set; } = 10;
private Jma? jmaUp;
private Jma? jmaLo;
protected LineSeries? UbSeries;
protected LineSeries? LbSeries;
protected string? SourceName;
public static int MinHistoryDepths => 2;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public JbandsIndicator()
{
Name = "JBANDS - Mark Jurik's Bands";
Description = "Upper and Lower Bands.";
SeparateWindow = false;
UbSeries = new("UB", Color.Blue, 2, LineStyle.Solid);
LbSeries = new("LB", Color.Red, 2, LineStyle.Solid);
AddLineSeries(UbSeries);
AddLineSeries(LbSeries);
}
protected override void OnInit()
{
jmaUp = new(Periods, phase: Phase);
jmaLo = new(Periods, phase: Phase);
SourceName = Source.ToString();
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TBar input = IndicatorExtensions.GetInputBar(this, args);
jmaUp!.Calc(input.High);
jmaLo!.Calc(input.Low);
UbSeries!.SetValue(jmaUp.UpperBand);
LbSeries!.SetValue(jmaLo.LowerBand);
}
public override string ShortName => $"JBands ({Periods}:{Phase})";
}
+23 -6
View File
@@ -6,11 +6,27 @@ namespace QuanTAlib;
public class JvoltyIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
public int Periods { get; set; } = 20;
public int Periods { get; set; } = 14;
private Jvolty? jvolty;
[InputParameter("Data source", sortIndex: 5, variants: [
"Open", SourceType.Open,
"High", SourceType.High,
"Low", SourceType.Low,
"Close", SourceType.Close,
"HL/2 (Median)", SourceType.HL2,
"OC/2 (Midpoint)", SourceType.OC2,
"OHL/3 (Mean)", SourceType.OHL3,
"HLC/3 (Typical)", SourceType.HLC3,
"OHLC/4 (Average)", SourceType.OHLC4,
"HLCC/4 (Weighted)", SourceType.HLCC4
])]
public SourceType Source { get; set; } = SourceType.Close;
private Jma? jma;
protected LineSeries? JvoltySeries;
public static int MinHistoryDepths => 2;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public JvoltyIndicator()
@@ -25,16 +41,17 @@ public class JvoltyIndicator : Indicator, IWatchlistIndicator
protected override void OnInit()
{
jvolty = new (Periods);
jma = new(Periods);
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TBar input = IndicatorExtensions.GetInputBar(this, args);
TValue result = jvolty!.Calc(input);
TValue input = this.GetInputValue(args, Source);
jma!.Calc(input);
JvoltySeries!.SetValue(jma.Volty);
JvoltySeries!.SetValue(result.Value);
}
public override string ShortName => $"JVOLTY ({Periods})";
+67
View File
@@ -0,0 +1,67 @@
using System.Drawing;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class RsiIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Periods", sortIndex: 1, 1, 2000, 1, 0)]
public int Periods { get; set; } = 14;
[InputParameter("Data source", sortIndex: 5, variants: [
"Open", SourceType.Open,
"High", SourceType.High,
"Low", SourceType.Low,
"Close", SourceType.Close,
"HL/2 (Median)", SourceType.HL2,
"OC/2 (Midpoint)", SourceType.OC2,
"OHL/3 (Mean)", SourceType.OHL3,
"HLC/3 (Typical)", SourceType.HLC3,
"OHLC/4 (Average)", SourceType.OHLC4,
"HLCC/4 (Weighted)", SourceType.HLCC4
])]
public SourceType Source { get; set; } = SourceType.Close;
[InputParameter("Show cold values", sortIndex: 21)]
public bool ShowColdValues { get; set; } = true;
private Rsi? rsi;
protected string? SourceName;
protected LineSeries? RsiSeries;
public int MinHistoryDepths => Periods + 1;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public RsiIndicator()
{
Name = "RSI - Relative Strength Index";
Description = "Measures the speed and magnitude of recent price changes to evaluate overbought or oversold conditions.";
SeparateWindow = true;
SourceName = Source.ToString();
RsiSeries = new($"RSI {Periods}", Color.Blue, 2, LineStyle.Solid);
AddLineSeries(RsiSeries);
}
protected override void OnInit()
{
rsi = new Rsi(Periods);
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TValue input = this.GetInputValue(args, Source);
rsi!.Calc(input);
RsiSeries!.SetValue(rsi.Value);
RsiSeries!.SetMarker(0, Color.Transparent);
}
public override string ShortName => $"RSI ({Periods}:{SourceName})";
#pragma warning disable CA1416 // Validate platform compatibility
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
this.PaintSmoothCurve(args, RsiSeries!, rsi!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2);
}
}
+67
View File
@@ -0,0 +1,67 @@
using System.Drawing;
using TradingPlatform.BusinessLayer;
namespace QuanTAlib;
public class RsxIndicator : Indicator, IWatchlistIndicator
{
[InputParameter("Rsi Period", sortIndex: 1, 1, 2000, 1, 0)]
public int Period { get; set; } = 14;
[InputParameter("Data source", sortIndex: 5, variants: [
"Open", SourceType.Open,
"High", SourceType.High,
"Low", SourceType.Low,
"Close", SourceType.Close,
"HL/2 (Median)", SourceType.HL2,
"OC/2 (Midpoint)", SourceType.OC2,
"OHL/3 (Mean)", SourceType.OHL3,
"HLC/3 (Typical)", SourceType.HLC3,
"OHLC/4 (Average)", SourceType.OHLC4,
"HLCC/4 (Weighted)", SourceType.HLCC4
])]
public SourceType Source { get; set; } = SourceType.Close;
[InputParameter("Show cold values", sortIndex: 21)]
public bool ShowColdValues { get; set; } = true;
private Rsx? rsx;
protected string? SourceName;
protected LineSeries? RsxSeries;
public int MinHistoryDepths => Period + 1;
int IWatchlistIndicator.MinHistoryDepths => MinHistoryDepths;
public RsxIndicator()
{
Name = "RSX - Jurik Trend Strengt Index";
Description = "Measures the speed and magnitude of recent price changes to evaluate overbought or oversold conditions.";
SeparateWindow = true;
SourceName = Source.ToString();
RsxSeries = new($"RSX {Period}", Color.Blue, 2, LineStyle.Solid);
AddLineSeries(RsxSeries);
}
protected override void OnInit()
{
rsx = new(Period);
base.OnInit();
}
protected override void OnUpdate(UpdateArgs args)
{
TValue input = this.GetInputValue(args, Source);
rsx!.Calc(input);
RsxSeries!.SetValue(rsx.Value);
RsxSeries!.SetMarker(0, Color.Transparent);
}
public override string ShortName => $"RSX ({Period}:{SourceName})";
#pragma warning disable CA1416 // Validate platform compatibility
public override void OnPaintChart(PaintChartEventArgs args)
{
base.OnPaintChart(args);
this.PaintSmoothCurve(args, RsxSeries!, rsx!.WarmupPeriod, showColdValues: ShowColdValues, tension: 0.2);
}
}