diff --git a/.github/workflows/main_automation.yml b/.github/workflows/main_automation.yml
index e84ae92e..53c6ac2a 100644
--- a/.github/workflows/main_automation.yml
+++ b/.github/workflows/main_automation.yml
@@ -57,10 +57,13 @@ jobs:
run: dotnet build ./Quantower/Quantower.csproj --verbosity normal --configuration Release --nologo
- name: dotnet Test
+ if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet test ./Tests/Tests.csproj --verbosity normal --configuration Release --nologo
- name: DotCover Test XML
+ if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet dotcover test ./Tests/Tests.csproj --verbosity normal --framework net7.0 --dcReportType=DetailedXML --dcoutput=./coveragereport.xml
- name: DotCover Test HTML
+ if: ${{ github.ref == 'refs/heads/dev' }}
run: dotnet dotcover test ./Tests/Tests.csproj --verbosity normal --framework net7.0 --dcReportType=HTML --dcoutput=./coveragereport.html
# - name: dotnet-coverage
# run: dotnet-coverage collect 'dotnet test' -f xml -o './coverage.xml'
@@ -72,15 +75,18 @@ jobs:
run: dotnet sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
- name: CodeCov run
+ if: ${{ github.ref == 'refs/heads/dev' }}
run: codecov -f ./coveragereport.xml -v -t ${{ secrets.CODECOV_TOKEN }}
- name: Codacy coverage reporter
+ if: ${{ github.ref == 'refs/heads/dev' }}
uses: codacy/codacy-coverage-reporter-action@v1
with:
project-token: ${{ secrets.CODACY_PROJECT_TOKEN }}
coverage-reports: ./coveragereport.xml
- name: Release
+ if: ${{ github.ref == 'refs/heads/main' }}
uses: marvinpinto/action-automatic-releases@latest
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
@@ -90,6 +96,7 @@ jobs:
files: /Quantower/Settings/Scripts/Indicators/QuanTAlib/*.dll
- name: Authenticate to Github packages source
+ if: ${{ github.ref == 'refs/heads/main' }}
run: dotnet nuget add source
--username mihakralj
--password ${{ secrets.GITHUB_TOKEN }}
@@ -97,6 +104,7 @@ jobs:
--name github "https://nuget.pkg.github.com/mihakralj/index.json"
- name: Push package to github
+ if: ${{ github.ref == 'refs/heads/main' }}
run: dotnet nuget push '.\Source\bin\Release\QuanTAlib.*.nupkg'
--api-key ${{ secrets.GITHUB_TOKEN }}
--source https://nuget.pkg.github.com/mihakralj/index.json
diff --git a/Source/Trends/HWMA_Series.cs b/Source/Trends/HWMA_Series.cs
new file mode 100644
index 00000000..50754285
--- /dev/null
+++ b/Source/Trends/HWMA_Series.cs
@@ -0,0 +1,57 @@
+namespace QuanTAlib;
+using System;
+
+/*
+HWMA: Holt-Winter Moving Average
+ Indicator HWMA (Holt-Winter Moving Average) is a three-parameter moving
+ average by the Holt-Winter method; Holt-Winters Exponential Smoothing is
+ used for forecasting time series data that exhibits both a trend and a
+ seasonal variation.
+
+
+Sources:
+ https://timeseriesreasoning.com/contents/holt-winters-exponential-smoothing/
+ https://www.mql5.com/en/code/20856
+
+nA - smoothed series (from 0 to 1)
+nB - assess the trend (from 0 to 1)
+nC - assess seasonality (from 0 to 1)
+
+F[i] = (1-nA) * (F[i-1] + V[i-1] + 0.5 * A[i-1]) + nA * Price[i]
+V[i] = (1-nB) * (V[i-1] + A[i-1]) + nB * (F[i] - F[i-1])
+A[i] = (1-nC) * A[i-1] + nC * (V[i] - V[i-1])
+HWMA[i] = F[i] + V[i] + 0.5 * A[i]
+
+ */
+
+public class HWMA_Series : Single_TSeries_Indicator {
+ double _nA, _nB, _nC;
+ double _pF, _pV, _pA;
+ double _ppF, _ppV, _ppA;
+
+ public HWMA_Series(TSeries source, double nA = 0.2, double nB = 0.1, double nC = 0.1, bool useNaN = false) : base(source, 0, useNaN) {
+
+ _nA = nA;
+ _nB = nB;
+ _nC = nC;
+ if (this._data.Count > 0) { base.Add(this._data); }
+ }
+ public override void Add((DateTime t, double v) TValue, bool update) {
+ double _F, _V, _A;
+ if (this.Count == 0) { _pF = TValue.v; _pA = _pV = 0; }
+
+ if (update) { _pF = _ppF; _pV = _ppV; _pA = _ppA; }
+ else { _ppF = _pF; _ppV = _pV; _ppA = _pA; }
+
+ _F = (1 - _nA) * (_pF + _pV + 0.5 * _pA) + _nA * TValue.v;
+ _V = (1 - _nB) * (_pV + _pA) + _nB * (_F - _pF);
+ _A = (1 - _nC) * _pA + _nC * (_V - _pV);
+
+ double _hwma = _F + _V + 0.5 * _A;
+ _pF = _F;
+ _pV = _V;
+ _pA = _A;
+
+ base.Add((TValue.t, _hwma), update, _NaN);
+ }
+}
diff --git a/Source/Trends/JMA_Series.cs b/Source/Trends/JMA_Series.cs
index af37b43d..0a8b201d 100644
--- a/Source/Trends/JMA_Series.cs
+++ b/Source/Trends/JMA_Series.cs
@@ -91,9 +91,8 @@ public class JMA_Series : Single_TSeries_Indicator {
/// from avolty to rolty
double rvolty = (avolty != 0) ? volty / avolty : 0;
- double len1 = (Math.Log(Math.Sqrt(0.5 * (_p - 1))) / Math.Log(2.0)) + 2;
- if (len1 < 0)
- len1 = 0;
+ double len1 = (Math.Log(Math.Sqrt(2.0 * _p)) / Math.Log(2.0)) + 2;
+ if (len1 < 0) len1 = 0;
double pow1 = Math.Max(len1 - 2.0, 0.5);
if (rvolty > Math.Pow(len1, 1.0 / pow1))
rvolty = Math.Pow(len1, 1.0 / pow1);
@@ -102,7 +101,7 @@ public class JMA_Series : Single_TSeries_Indicator {
//// from rvolty to second smoothing
double pow2 = Math.Pow(rvolty, pow1);
- double len2 = Math.Sqrt(0.5 * (_p - 1)) * len1;
+ double len2 = Math.Sqrt(0.5 * (_p - 2)) * len1;
Kv = Math.Pow(len2 / (len2 + 2), Math.Sqrt(pow2));
double beta = 0.45 * (_p - 1) / (0.45 * (_p - 1) + 2);
double alpha = Math.Pow(beta * 1.1, pow2);
@@ -120,6 +119,6 @@ public class JMA_Series : Single_TSeries_Indicator {
double jma = prev_jma + det1;
prev_jma = jma;
- base.Add((TValue.t, ma1), update, _NaN);
+ base.Add((TValue.t, jma), update, _NaN);
}
}
\ No newline at end of file
diff --git a/Tests/Series/Update.cs b/Tests/Series/Update.cs
index 80335697..e477da9f 100644
--- a/Tests/Series/Update.cs
+++ b/Tests/Series/Update.cs
@@ -175,7 +175,18 @@ public class Update {
Assert.Equal(lastLen, QL.Count); // same size
Assert.Equal(lastCalc, QL.Last()); // same data
}
- [Fact] public void JMA() {
+ [Fact]
+ public void HWMA() {
+ HWMA_Series QL = new(source: bars.Close);
+ var lastData = bars.Close.Last();
+ var lastCalc = QL.Last();
+ int lastLen = QL.Count;
+ QL.Add((DateTime.Today, 0), update: true);
+ QL.Add(lastData, update: true);
+ Assert.Equal(lastLen, QL.Count); // same size
+ Assert.Equal(lastCalc, QL.Last()); // same data
+ }
+ [Fact] public void JMA() {
JMA_Series QL = new(source: bars.Close, period: period);
var lastData = bars.Close.Last();
var lastCalc = QL.Last();
diff --git a/Tests/Validations/Trends/Pandas_TA.cs b/Tests/Validations/Trends/Pandas_TA.cs
index 5549a5c2..7da08900 100644
--- a/Tests/Validations/Trends/Pandas_TA.cs
+++ b/Tests/Validations/Trends/Pandas_TA.cs
@@ -165,7 +165,18 @@ public class PandasTA : IDisposable
Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
}
- }
+ }
+ [Fact] void HWMA() {
+ HWMA_Series QL = new(bars.Close, useNaN: false);
+ var pta = df.ta.hwma(close: df.close);
+ for (int i = QL.Length; i > QL.Length-sample; i--)
+ {
+ double QL_item = QL[i - 1].v;
+ double PanTA_item = (double)pta[i - 1];
+ Assert.InRange(PanTA_item! - QL_item, -Math.Exp(-digits), Math.Exp(-digits));
+ }
+
+ }
[Fact] void KAMA() {
KAMA_Series QL = new(bars.Close, period);
var pta = df.ta.kama(close: df.close, length: period);
diff --git a/docs/HWMA.md b/docs/HWMA.md
new file mode 100644
index 00000000..6102933e
--- /dev/null
+++ b/docs/HWMA.md
@@ -0,0 +1,4 @@
+# HWMA: Holt-Winter Moving Average
+nA = 0.5; nB = 0.3; nC = 0.01;
+
+
\ No newline at end of file
diff --git a/docs/MAMA.md b/docs/MAMA.md
new file mode 100644
index 00000000..19dacbb0
--- /dev/null
+++ b/docs/MAMA.md
@@ -0,0 +1,4 @@
+# MAMA: MESA Adaptive Moving Average
+period = 10
+
+
\ No newline at end of file
diff --git a/docs/_sidebar.md b/docs/_sidebar.md
index 52a8a6dd..f59cf77c 100644
--- a/docs/_sidebar.md
+++ b/docs/_sidebar.md
@@ -3,19 +3,20 @@
* [List of all Indicators](indicators.md "Indicators coverage")
* [SMA - Simple Moving Average](SMA.md)
- * [RMA - WildeR Moving Average](RMA.md)
* [EMA - Exponential Moving Average](EMA.md)
* [WMA - Weighted Moving Average](WMA.md)
+ * [T3 - Tillson T3 Exponential MA](T3.md)
* [SMMA - Smoothed Moving Average](SMMA.md)
- * [DWMA - Double Weighted Moving Average](DWMA.md)
* [TRIMA - Triangular Moving Average](TRIMA.md)
+ * [DWMA - Double Weighted Moving Average](DWMA.md)
* [DEMA - Double Exponential MA](DEMA.md)
* [TEMA - Triple Exponential MA](TEMA.md)
- * [T3 - Tillson T3 Exponential MA](T3.md)
+ * [ALMA - Arnaud Legoux Moving Average](ALMA.md)
* [HMA - Hull Moving Average](HMA.md)
* [HEMA - Hull/Exponential Moving Average](HEMA.md)
+ * [HWMA - Holt-Winter Moving Average](HWMA.md)
+ * [MAMA - MESA Adaptive Moving Average](MAMA.md)
* [KAMA - Kaufman Adaptive Moving Average](KAMA.md)
- * [ALMA - Arnaud Legoux Moving Average](ALMA.md)
* [ZLEMA - Zero-Lag Exponential MA](ZLEMA.md)
* [JMA - Jurik Moving Average](JMA.md)
diff --git a/docs/img/HWMA_chart.svg b/docs/img/HWMA_chart.svg
new file mode 100644
index 00000000..660fa53f
--- /dev/null
+++ b/docs/img/HWMA_chart.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/docs/img/MAMA_chart.svg b/docs/img/MAMA_chart.svg
index 3a17f18e..fd2cef35 100644
--- a/docs/img/MAMA_chart.svg
+++ b/docs/img/MAMA_chart.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/img/T3_chart.svg b/docs/img/T3_chart.svg
index c1d87c5f..906a89ab 100644
--- a/docs/img/T3_chart.svg
+++ b/docs/img/T3_chart.svg
@@ -1 +1 @@
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/docs/indicators.md b/docs/indicators.md
index bec75679..514e1c35 100644
--- a/docs/indicators.md
+++ b/docs/indicators.md
@@ -62,7 +62,7 @@
|HEMA - Hull/EMA Average|`HEMA_Series`||||
|Hilbert Transform Instantaneous Trendline||HT_TRENDLINE|GetHtTrendline||
|⭐HMA - Hull Moving Average|`HMA_Series`||✔️GetHma|✔️hma|✔️hma|
-|HWMA - Holt-Winter Moving Average||||hwma|
+|HWMA - Holt-Winter Moving Average|`HWMA_Series`|||✔️hwma|
|JMA - Jurik Moving Average|`JMA_Series`|||jma||
|KAMA - Kaufman's Adaptive Moving Average|`KAMA_Series`|✔️KAMA|✔️GetKama|✔️kama|✔️kama|
|KDJ - KDJ Indicator (trend reversal)||||kdj|