From 80d82e58634744f2ade4f947d002a1a8cf608319 Mon Sep 17 00:00:00 2001 From: Miha Kralj Date: Tue, 15 Nov 2022 16:22:07 -0800 Subject: [PATCH] ZSCORE --- .gitignore | 1 + Source/Feeds/Yahoo_Feed.cs | 21 +++----- Source/QuanTAlib.csproj | 9 +++- Source/Statistics/ZSCORE_Series.cs | 51 ++++++++++++++++++ Tests/Validations/Pandas_TA.cs | 35 ++++++++++-- Tests/Validations/Skender_Stock.cs | 32 ++++++++--- docs/.md | 87 ------------------------------ docs/readme.md | 56 +++++++++---------- 8 files changed, 149 insertions(+), 143 deletions(-) create mode 100644 Source/Statistics/ZSCORE_Series.cs delete mode 100644 docs/.md diff --git a/.gitignore b/.gitignore index 5c1b519b..9e8f3128 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ .vscode/ *.deps.json .Sandbox/ +.sonarlint/ .DS_Store # User-specific files (MonoDevelop/Xamarin Studio) diff --git a/Source/Feeds/Yahoo_Feed.cs b/Source/Feeds/Yahoo_Feed.cs index 5cbcdd86..75b7c53d 100644 --- a/Source/Feeds/Yahoo_Feed.cs +++ b/Source/Feeds/Yahoo_Feed.cs @@ -22,24 +22,17 @@ public class Yahoo_Feed : TBars System.Net.Http.HttpClient client = new(); var msg = client.GetStringAsync(requestUrl).Result; var jresult = JsonSerializer.Deserialize(msg).RootElement; - JsonElement json = new(); - JsonElement datetime = new(); - JsonElement open = new(); - JsonElement high = new(); - JsonElement low = new(); - JsonElement close = new(); - JsonElement volume = new(); - jresult.TryGetProperty("chart",out json); + jresult.TryGetProperty("chart",out JsonElement json); json.TryGetProperty("result",out json); - json[0].TryGetProperty("timestamp",out datetime); + json[0].TryGetProperty("timestamp",out JsonElement datetime); json[0].TryGetProperty("indicators",out json); json.TryGetProperty("quote",out json); - json[0].TryGetProperty("open",out open); - json[0].TryGetProperty("high",out high); - json[0].TryGetProperty("low",out low); - json[0].TryGetProperty("close",out close); - json[0].TryGetProperty("volume",out volume); + json[0].TryGetProperty("open",out JsonElement open); + json[0].TryGetProperty("high",out JsonElement high); + json[0].TryGetProperty("low",out JsonElement low); + json[0].TryGetProperty("close",out JsonElement close); + json[0].TryGetProperty("volume",out JsonElement volume); for (int i=0; iQuanTAlib2.png https://raw.githubusercontent.com/mihakralj/QuanTAlib/main/.github/QuanTAlib2.png True + ..\.sonarlint\mihakralj_quantalibcsharp.ruleset + + + True @@ -64,10 +68,11 @@ - - All + all + runtime; build; native; contentfiles; analyzers; buildtransitive + \ No newline at end of file diff --git a/Source/Statistics/ZSCORE_Series.cs b/Source/Statistics/ZSCORE_Series.cs new file mode 100644 index 00000000..5b6865eb --- /dev/null +++ b/Source/Statistics/ZSCORE_Series.cs @@ -0,0 +1,51 @@ +namespace QuanTAlib; +using System; + +/* +ZSCORE: number of standard deviations from SMA + Z-score describes a value's relationship to the mean of a series, as measured in + terms of standard deviations from the mean. If a Z-score is 0, it indicates that + the data point's score is identical to the mean score. A Z-score of 1.0 would + indicate a value that is one standard deviation from the mean. Z-scores may be + positive or negative, with a positive value indicating the score is above the + mean and a negative score indicating it is below the mean. + +Sources: + https://en.wikipedia.org/wiki/Z-score + https://www.investopedia.com/terms/z/zscore.asp + +Calculation: + std = std * STDEV(close, length) + mean = SMA(close, length) + ZSCORE = (close - mean) / std + + */ + +public class ZSCORE_Series : Single_TSeries_Indicator +{ + public ZSCORE_Series(TSeries source, int period, bool useNaN = false) : base(source, period, useNaN) + { + if (base._data.Count > 0) { base.Add(base._data); } + } + private readonly System.Collections.Generic.List _buffer = new(); + + public override void Add((System.DateTime t, double v) TValue, bool update) + { + if (update) { _buffer[_buffer.Count - 1] = TValue.v; } + else { _buffer.Add(TValue.v); } + if (_buffer.Count > this._p && this._p != 0) { _buffer.RemoveAt(0); } + + double _sma = 0; + for (int i = 0; i < _buffer.Count; i++) { _sma += _buffer[i]; } + _sma /= this._buffer.Count; + + double _pvar = 0; + for (int i = 0; i < _buffer.Count; i++) { _pvar += (_buffer[i] - _sma) * (_buffer[i] - _sma); } + _pvar /= this._buffer.Count; + double _psdev = Math.Sqrt(_pvar); + double _zscore = (_psdev == 0) ? double.NaN : (TValue.v - _sma) / _psdev; + + var result = (TValue.t, (this.Count < this._p - 1 && this._NaN) ? double.NaN : _zscore); + base.Add(result, update); + } +} \ No newline at end of file diff --git a/Tests/Validations/Pandas_TA.cs b/Tests/Validations/Pandas_TA.cs index 5991fedf..b359139f 100644 --- a/Tests/Validations/Pandas_TA.cs +++ b/Tests/Validations/Pandas_TA.cs @@ -57,8 +57,9 @@ public class PandasTA : IDisposable public void Dispose() { - PythonEngine.Shutdown(); - } + PythonEngine.Shutdown(); + GC.SuppressFinalize(this); + } [Fact] void HL2() @@ -192,9 +193,33 @@ public class PandasTA : IDisposable TEMA_Series QL = new(bars.Close, period, false); var pta = df.ta.tema(close: df.close, length: period); Assert.Equal(Math.Round((double)pta.tail(1), 7), Math.Round(QL.Last().v, 7)); - } - - [Fact] + } + + [Fact] + void SDEV() + { + SDEV_Series QL = new(bars.Close, period, useNaN: false); + var pta = df.ta.stdev(close: df.close, length: period, ddof: 0); + Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + } + + [Fact] + void SSDEV() + { + SSDEV_Series QL = new(bars.Close, period, useNaN: false); + var pta = df.ta.stdev(close: df.close, length: period, ddof: 1); + Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + } + + [Fact] + void ZSCORE() + { + ZSCORE_Series QL = new(bars.Close, period, useNaN: false); + var pta = df.ta.zscore(close: df.close, length: period, ddof: 0); + Assert.Equal(Math.Round((double)pta.tail(1), 4), Math.Round(QL.Last().v, 4)); + } + + [Fact] void ENTP() { ENTP_Series QL = new(bars.Close, period, useNaN: false); diff --git a/Tests/Validations/Skender_Stock.cs b/Tests/Validations/Skender_Stock.cs index 33664ee5..2f895e1f 100644 --- a/Tests/Validations/Skender_Stock.cs +++ b/Tests/Validations/Skender_Stock.cs @@ -80,7 +80,16 @@ public class Skender_Stock Assert.Equal(Math.Round((double)SK.Last().Mad!, 6), Math.Round(QL.Last().v, 6)); } - [Fact] + [Fact] + public void MSE() + { + MSE_Series QL = new(bars.Close, period, false); + var SK = quotes.GetSmaAnalysis(period); + + Assert.Equal(Math.Round((double)SK.Last().Mse!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] public void MAPE() { MAPE_Series QL = new(bars.Close, period, false); @@ -115,7 +124,7 @@ public class Skender_Stock ADL_Series QL = new(bars, false); var SK = quotes.GetAdl(); - Assert.Equal(Math.Round((double)SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5)); + Assert.Equal(Math.Round(SK.Last().Adl!, 5), Math.Round(QL.Last().v, 5)); } [Fact] @@ -214,7 +223,16 @@ public class Skender_Stock Assert.Equal(Math.Round((double)SK.Last().StdDev!, 6), Math.Round(QL.Last().v, 6)); } - [Fact] + [Fact] + public void ZSCORE() + { + ZSCORE_Series QL = new(bars.Close, period, useNaN: false); + var SK = quotes.GetStdDev(period); + + Assert.Equal(Math.Round((double)SK.Last().ZScore!, 6), Math.Round(QL.Last().v, 6)); + } + + [Fact] public void LINREG() { LINREG_Series QL = new(bars.Close, period, useNaN: false); @@ -241,7 +259,7 @@ public class Skender_Stock TSeries QL = bars.HL2; var SK = quotes.GetBaseQuote(CandlePart.HL2); - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -250,7 +268,7 @@ public class Skender_Stock TSeries QL = bars.OC2; var SK = quotes.GetBaseQuote(CandlePart.OC2); - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -259,7 +277,7 @@ public class Skender_Stock TSeries QL = bars.HLC3; var SK = quotes.GetBaseQuote(CandlePart.HLC3); - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } [Fact] @@ -268,7 +286,7 @@ public class Skender_Stock TSeries QL = bars.OHL3; var SK = quotes.GetBaseQuote(CandlePart.OHL3); - Assert.Equal(Math.Round((double)SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); + Assert.Equal(Math.Round(SK.Last().Value!, 6), Math.Round(QL.Last().v, 6)); } [Fact] diff --git a/docs/.md b/docs/.md deleted file mode 100644 index d4f34736..00000000 --- a/docs/.md +++ /dev/null @@ -1,87 +0,0 @@ - -## 1. Prepare the Peloton tablet - -Stop Peloton overlay app: -- tap on Settings in the top right corner and select Device Settings -- tap Apps and scroll down to find and tap Peloton app (not Peloton Launcher, just Peloton) -- tap FORCE STOP to stop the app overlay -- confrm by tapping OK - -Turn on developer mode -- return to Settings page -- tap About tablet in System section -- tap Build number repeatedly until you activate developer mode - -Enable USB debugging -- return to Settings page -- tap (now visible) Developer options in System section -- scroll down to find USB Debugging option -- Enable USB debugging -- Confirm by tapping OK - -## 3. Prepare the PC with Zwift/Rouvy - -- Create your Splashtop account https://my.splashtop.com/login -- Download and install Splashtop Streamer https://www.splashtop.com/downloads#pers -- Download Android Platform Tools https://developer.android.com/studio/releases/platform-tools -- Download Nova launcher APK (or any other launcher that works on Android 7) https://apkpure.com/nova-launcher/com.teslacoilsw.launcher/download/62019-APK -- Download Splashtop APK https://apkpure.com/splashtop-personal-access/com.splashtop.remote.pad.v2 -- Unzip Android tools into a new folder -- move both APKs to the same folder -- Run Command Prompt (CMD) and move to the same folder -- Launch Android Debuging Bridge: adb start-server -- Connect PC and Peloton tablet with USB cable -- Peloton tablet will check for confirmation; Accept debugging over USB -- Verify connectivity on PC in the Command window: adb devices - -## 4. Side-load APKs - -- Execute the following three commands on PC: - adb shell settings put secure install_non_market_apps 1 - adb install - adb install -- Disconnect USB cable -- On Peloton tablet tap Peloton 'P' logo at the bottom -- Select Nova as a default launcher -- Accept all defaults for Nova launcher - you can customize it later - - -- (optional) Bring Peloton and Splashtop icons to the main page of Nova launcher -- Choosing Peloton launches Peloton app; Choosing Splashtop launches Splashtop app -- Swiping down from the top of the screen reveals the hidden 'P' launcher button - -## 5. Connect Peloton tablet and PC - -- Launch Splashtop app on Peloton tablet -- Login with Splashtop credentials -- Connect to PC that runs Splashtop streamer (and Zwift/Rouvy) -- Launch Zwift/Rouvy - -## 5. Enable sensors - -- (optional): buy ANT+ USB dongle https://www.amazon.com/s?k=ant%2B+USB+stick - -Peloton Tread: - Speed: Runn https://npe-inc.com/runn-smart-treadmill-sensor-2/ - (or Stryd https://www.stryd.com/us/en) - Cadence: Garmin foodpod (or Stryd) - Heartrate: any HR monitor (BT or ANT+) https://www.amazon.com/s?k=bluetooth+HR+monitor - Power: Stryd - -Peloton Bike (gen1): - Power & Cadence: DFC (Data Fitness Connector) https://www.crowdsupply.com/intelligenate/data-fitness-connector - Heartrate:vany HR monitor (BT or ANT+) - -## 6. Navigation - -Nova is now a default launcher on Android tablet, but on Tread we need to run Peloton app in the background to prevent locking of treadmill: - -- Launch Peloton app -- Swipe down from the top and return to Nova launcher -- Launch Splashtop app -- Connect to PC -- Launch Zwift or Rouvy -- Connect all sensors -- Run/Ride! - - \ No newline at end of file diff --git a/docs/readme.md b/docs/readme.md index 5bd1f513..2db4cd98 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -38,13 +38,13 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | **BASIC TRANSFORMS** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** | |--|:--:|:--:|:--:|:--:| | ⭐ OC2 - (Open+Close)/2 |️ `.OC2` || CandlePart.OC2 || -| ⭐ HL2 - Median Price | `.HL2` | MEDPRICE | CandlePart.HL2 || -| ⭐ HLC3 - Typical Price | `.HLC3` | TYPPRICE | CandlePart.HLC3 || +| ⭐ HL2 - Median Price | `.HL2` | MEDPRICE | CandlePart.HL2 | hl2 | +| ⭐ HLC3 - Typical Price | `.HLC3` | TYPPRICE | CandlePart.HLC3 | hlc3 | | ⭐ OHL3 - (Open+High+Low)/3 | `.OHL3` || CandlePart.OHL3 || -| ⭐ OHLC4 - Average Price | `.OHLC4` | AVGPRICE |️ CandlePart.OHLC4 || +| ⭐ OHLC4 - Average Price | `.OHLC4` | AVGPRICE |️ CandlePart.OHLC4 | ohlc4 | | ⭐ HLCC4 - Weighted Price | `.HLCC4` | WCLPRICE | CandlePart.HLCC4 || -| ⭐ MIDPOINT - Midpoint value | `MIDPOINT_Series` | MIDPOINT ||| -| ⭐ MIDPRICE - Midpoint price | `MIDPRICE_Series` | MIDPRICE ||| +| ⭐ MIDPOINT - Midpoint value | `MIDPOINT_Series` | MIDPOINT || midpoint | +| ⭐ MIDPRICE - Midpoint price | `MIDPRICE_Series` | MIDPRICE || midprice | | ⭐ MAX - Max value | `MAX_Series` | MAX ||| | ⭐ MIN - Min value | `MIN_Series` | MIN ||| | ⭐ SUM - Summation | `SUM_Series` | SUM ||| @@ -63,54 +63,54 @@ See [Getting Started](https://github.com/mihakralj/QuanTAlib/blob/main/Docs/gett | ⭐ MAD - Mean Absolute Deviation | `MAD_Series` || GetSma | mad | | ⭐ MAPE - Mean Absolute Percent Error | `MAPE_Series` || GetSma || | ⭐ MED - Median value | `MED_Series` ||| median | -| ✔️ MSE - Mean Squared Error | `MSE_Series` || GetSma || -| ⛔ SKEW - Skewness ||||| -| ⭐ SDEV - Standard Deviation (Volatility) | `SDEV_Series` | STDDEV ||| -| ✔️ SSDEV - Sample Standard Deviation | `SSDEV_Series` |||| +| ⭐ MSE - Mean Squared Error | `MSE_Series` || GetSma || +| ⛔ SKEW - Skewness |||| skew | +| ⭐ SDEV - Standard Deviation (Volatility) | `SDEV_Series` | STDDEV | GetStdDev | stdev | +| ⭐ SSDEV - Sample Standard Deviation | `SSDEV_Series` ||| stdev | | ✔️ SMAPE - Symmetric Mean Absolute Percent Error | `SMAPE_Series` |||| | ⭐ VAR - Population Variance | `VAR_Series` | VAR || variance | | ⭐ SVAR - Sample Variance | `SVAR_Series` ||| variance | -| ⛔ QUANT - Quantile ||||| +| ⛔ QUANTILE - Quantile |||| quantile | | ✔️ WMAPE - Weighted Mean Absolute Percent Error | `WMAPE_Series` |||| -| ⛔ ZSCORE - Number of standard deviations from mean ||||| +| ⭐ ZSCORE - Number of standard deviations from mean | ZSCORE_Series || GetStdDev | zscore | |||||| | **TREND INDICATORS & AVERAGES** | **QuanTAlib** | **TA-LIB** | **Skender** | **Pandas TA** | | ⛔ AFIRMA - Autoregressive Finite Impulse Response Moving Average ||||| -| ⭐ ALMA - Arnaud Legoux Moving Average | `ALMA_Series` || GetAlma || +| ⭐ ALMA - Arnaud Legoux Moving Average | `ALMA_Series` || GetAlma | alma | | ⛔ ARIMA - Autoregressive Integrated Moving Average ||||| | ⭐ DEMA - Double EMA Average | `DEMA_Series` | DEMA | GetDema | dema | | ⭐ EMA - Exponential Moving Average | `EMA_Series` || GetEma | ema | | ⛔ EPMA - Endpoint Moving Average ||| GetEpma || | ⛔ FRAMA - Fractal Adaptive Moving Average ||||| -| ⛔ FWMA - Fibonacci's Weighted Moving Average ||||| -| ⛔ HILO - Gann High-Low Activator ||||| +| ⛔ FWMA - Fibonacci's Weighted Moving Average |||| fwma | +| ⛔ HILO - Gann High-Low Activator |||| hilo | | ✔️ HEMA - Hull/EMA Average | `HEMA_Series` |||| | ⛔ Hilbert Transform Instantaneous Trendline || HT_TRENDLINE | GetHtTrendline || | ⭐ HMA - Hull Moving Average | `HMA_Series` || GetHma | hma | -| ⛔ HWMA - Holt-Winter Moving Average ||||| -| ✔️ JMA - Jurik Moving Average | `JMA_Series` |||| +| ⛔ HWMA - Holt-Winter Moving Average |||| hwma | +| ✔️ JMA - Jurik Moving Average | `JMA_Series` ||| jma | | ⭐ KAMA - Kaufman's Adaptive Moving Average | `KAMA_Series` | KAMA | GetKama | kama | -| ⛔ KDJ - KDJ Indicator (trend reversal) ||||| +| ⛔ KDJ - KDJ Indicator (trend reversal) |||| kdj | | ⛔ LSMA - Least Squares Moving Average ||||| -| ⭐ MACD - Moving Average Convergence/Divergence | `MACD_Series` | MACD | GetMacd || +| ⭐ MACD - Moving Average Convergence/Divergence | `MACD_Series` | MACD | GetMacd | macd | | ⛔ MAMA - MESA Adaptive Moving Average || MAMA | GetMama || -| ⛔ MCGD - McGinley Dynamic ||||| +| ⛔ MCGD - McGinley Dynamic |||| mcgd | | ⛔ MMA - Modified Moving Average ||||| | ⛔ PPMA - Pivot Point Moving Average ||||| -| ⛔ PWMA - Pascal's Weighted Moving Average ||||| +| ⛔ PWMA - Pascal's Weighted Moving Average |||| pwma | | ⭐ RMA - WildeR's Moving Average | `RMA_Series` ||| rma | -| ⛔ SINWMA - Sine Weighted Moving Average ||||| +| ⛔ SINWMA - Sine Weighted Moving Average |||| sinwma | | ⭐ SMA - Simple Moving Average | `SMA_Series` | SMA | GetSma | sma | | ⭐ SMMA - Smoothed Moving Average | `SMMA_Series` || GetSmma || -| ⛔ SSF - Ehler's Super Smoother Filter ||||| -| ⛔ SUP - Supertrend ||||| -| ⛔ SWMA - Symmetric Weighted Moving Average ||||| -| ⛔ T3 - Tillson T3 Moving Average || T3 | GetT3 || +| ⛔ SSF - Ehler's Super Smoother Filter |||| ssf | +| ⛔ SUPERTREND - Supertrend |||| supertrend | +| ⛔ SWMA - Symmetric Weighted Moving Average |||| swma | +| ⛔ T3 - Tillson T3 Moving Average || T3 | GetT3 | t3 | | ⭐ TEMA - Triple EMA Average | `TEMA_Series` | TEMA | GetTema | tema | -| ⭐ TRIMA - Triangular Moving Average | `TRIMA_Series` | TRIMA ||| +| ⭐ TRIMA - Triangular Moving Average | `TRIMA_Series` | TRIMA || trima | | ⛔ TSF - Time Series Forecast || TSF ||| -| ⛔ VIDYA - Variable Index Dynamic Average ||||| -| ⛔ VOR - Vortex Indicator ||||| +| ⛔ VIDYA - Variable Index Dynamic Average |||| vidya | +| ⛔ VORTEX - Vortex Indicator |||| vortex | | ⭐ WMA - Weighted Moving Average | `WMA_Series` | WMA | GetWma | wma | | ⭐ ZLEMA - Zero Lag EMA Average | `ZLEMA_Series` ||| zlma | ||||||