From c27147c1cdf77af5dde1711bb3adf98b29993db8 Mon Sep 17 00:00:00 2001
From: Dave Skender <8432125+DaveSkender@users.noreply.github.com>
Date: Sat, 29 Jun 2024 19:40:13 -0400
Subject: [PATCH] chore: code cleanup
---
Stock.Indicators.sln.DotSettings | 2 +
docs/pages/utilities.md | 16 +-
src/_common/Candles/Candles.Models.cs | 10 +-
src/_common/Candles/Candles.Utilities.cs | 2 +-
src/_common/Enums.cs | 44 ++---
src/_common/Generics/Pruning.cs | 18 +-
src/_common/Generics/Seek.cs | 13 +-
src/_common/Math/NullMath.cs | 10 +-
src/_common/Math/Numerix.cs | 36 ++--
src/_common/Observables/AbstractCache.cs | 133 ++++++---------
.../Observables/AbstractChainInChainOut.cs | 29 +---
.../Observables/AbstractChainInResultOut.cs | 29 +---
src/_common/Observables/AbstractProvider.cs | 154 +++++++++---------
.../Observables/AbstractQuoteInChainOut.cs | 29 +---
.../Observables/AbstractQuoteInQuoteOut.cs | 30 ++--
.../Observables/AbstractQuoteInResultOut.cs | 29 +---
src/_common/Observables/IStreamCache.cs | 10 +-
src/_common/Observables/IStreamObserver.cs | 49 ++++--
src/_common/Observables/IStreamProvider.cs | 80 +++++----
src/_common/Observables/QuoteProvider.cs | 11 +-
src/_common/ObsoleteV3.cs | 4 +-
src/_common/Quotes/Quote.Aggregates.cs | 38 ++---
src/_common/Quotes/Quote.Converters.cs | 97 ++++++-----
src/_common/Quotes/Quote.Models.cs | 4 +-
src/_common/Quotes/Quote.Validation.cs | 5 +
src/_common/Results/Result.Utilities.cs | 4 +-
.../Use (quote converter)/Use.Stream.cs | 8 +-
src/a-d/Adl/Adl.Api.cs | 13 +-
src/a-d/Adl/Adl.Common.cs | 6 +-
src/a-d/Adl/Adl.Series.cs | 2 +-
src/a-d/Adl/Adl.Stream.cs | 2 +-
src/a-d/Adl/info.xml | 17 --
src/a-d/Adx/Adx.Series.cs | 24 +--
src/a-d/Adx/Adx.Utilities.cs | 2 +-
src/a-d/Alligator/Alligator.Series.cs | 10 +-
src/a-d/Alligator/Alligator.Stream.cs | 36 ++--
src/a-d/Alma/Alma.Series.cs | 2 +-
src/a-d/Aroon/Aroon.Series.cs | 2 +-
src/a-d/Atr/Atr.Series.cs | 8 +-
src/a-d/AtrStop/AtrStop.Series.cs | 10 +-
src/a-d/Awesome/Awesome.Series.cs | 8 +-
src/a-d/Beta/Beta.Series.cs | 50 +++---
.../BollingerBands/BollingerBands.Series.cs | 14 +-
src/a-d/Bop/Bop.Series.cs | 8 +-
src/a-d/Cci/Cci.Series.cs | 6 +-
src/a-d/ChaikinOsc/ChaikinOsc.Series.cs | 4 +-
src/a-d/Chandelier/Chandelier.Series.cs | 8 +-
src/a-d/Chop/Chop.Series.cs | 17 +-
src/a-d/Cmf/Cmf.Series.cs | 4 +-
src/a-d/Cmo/Cmo.Series.cs | 11 +-
src/a-d/ConnorsRsi/ConnorsRsi.Series.cs | 2 +-
src/a-d/Correlation/Correlation.Series.cs | 20 +--
src/a-d/Dema/Dema.Series.cs | 10 +-
src/a-d/Dema/Dema.Utilities.cs | 2 +-
src/a-d/Doji/Doji.Api.cs | 6 -
src/a-d/Doji/Doji.Series.cs | 4 +-
src/a-d/Donchian/Donchian.Series.cs | 4 +-
src/a-d/Dpo/Dpo.Series.cs | 6 +-
src/a-d/Dynamic/Dynamic.Series.cs | 8 +-
src/e-k/ElderRay/ElderRay.Series.cs | 4 +-
src/e-k/Ema/Ema.Common.cs | 2 +-
src/e-k/Ema/Ema.Series.cs | 4 +-
src/e-k/Ema/Ema.Stream.cs | 7 +-
src/e-k/Epma/Epma.Series.cs | 4 +-
src/e-k/Fcb/Fcb.Series.cs | 4 +-
.../FisherTransform/FisherTransform.Series.cs | 20 +--
src/e-k/ForceIndex/ForceIndex.Series.cs | 18 +-
src/e-k/Fractal/Fractal.Series.cs | 12 +-
src/e-k/Gator/Gator.Series.cs | 16 +-
src/e-k/HeikinAshi/HeikinAshi.Series.cs | 2 +-
src/e-k/Hma/Hma.Series.cs | 16 +-
src/e-k/HtTrendline/HtTrendline.Series.cs | 51 +++---
src/e-k/Hurst/Hurst.Series.cs | 12 +-
src/e-k/Ichimoku/Ichimoku.Series.cs | 103 ++++++------
src/e-k/Kama/Kama.Models.cs | 2 +-
src/e-k/Kama/Kama.Series.cs | 18 +-
src/e-k/Kama/Kama.Utilities.cs | 2 +-
src/e-k/Keltner/Keltner.Series.cs | 6 +-
src/e-k/Kvo/Kvo.Series.cs | 24 +--
src/m-r/MaEnvelopes/MaEnvelopes.Api.cs | 2 +-
src/m-r/MaEnvelopes/MaEnvelopes.Series.cs | 86 +++++-----
src/m-r/Macd/Macd.Series.cs | 4 +-
src/m-r/Mama/Mama.Series.cs | 49 +++---
src/m-r/Marubozu/Marubozu.Common.cs | 16 +-
src/m-r/Marubozu/Marubozu.Series.cs | 4 +-
src/m-r/Mfi/Mfi.Series.cs | 16 +-
src/m-r/Obv/Obv.Series.cs | 2 +-
src/m-r/ParabolicSar/ParabolicSar.Series.cs | 17 +-
src/m-r/PivotPoints/PivotPoints.Models.cs | 6 +-
src/m-r/PivotPoints/PivotPoints.Series.cs | 102 ++++++------
src/m-r/PivotPoints/PivotPoints.Utilities.cs | 2 +-
src/m-r/Pivots/Pivots.Models.cs | 8 +-
src/m-r/Pivots/Pivots.Series.cs | 20 +--
src/m-r/Pmo/Pmo.Series.cs | 8 +-
src/m-r/Prs/Prs.Common.cs | 7 +-
src/m-r/Prs/Prs.Series.cs | 4 +-
src/m-r/Pvo/Pvo.Series.cs | 6 +-
src/m-r/Renko/Renko.Series.cs | 17 +-
src/m-r/Renko/RenkoAtr.Series.cs | 2 +-
src/m-r/Roc/Roc.Series.cs | 6 +-
src/m-r/RocWb/RocWb.Series.cs | 4 +-
src/m-r/RollingPivots/RollingPivots.Models.cs | 2 +-
src/m-r/RollingPivots/RollingPivots.Series.cs | 10 +-
.../RollingPivots/RollingPivots.Utilities.cs | 2 +-
src/m-r/Rsi/Rsi.Series.cs | 17 +-
src/s-z/Slope/Slope.Series.cs | 33 ++--
src/s-z/Sma/Sma.Api.cs | 9 -
src/s-z/Sma/Sma.Series.cs | 5 +-
src/s-z/Sma/Sma.Stream.cs | 7 +-
src/s-z/SmaAnalysis/Sma.Analysis.Api.cs | 16 ++
.../Sma.Analysis.Series.cs} | 6 +-
src/s-z/Smi/Smi.Series.cs | 16 +-
src/s-z/Smma/Smma.Series.cs | 6 +-
src/s-z/StarcBands/StarcBands.Series.cs | 8 +-
src/s-z/Stc/Stc.Series.cs | 6 +-
src/s-z/StdDev/StdDev.Series.cs | 4 +-
.../StdDevChannels/StdDevChannels.Series.cs | 26 +--
src/s-z/Stoch/Stoch.Api.cs | 2 +-
src/s-z/Stoch/Stoch.Common.cs | 2 +-
src/s-z/Stoch/Stoch.Series.cs | 124 +++++++-------
src/s-z/StochRsi/StochRsi.Series.cs | 8 +-
src/s-z/SuperTrend/SuperTrend.Series.cs | 8 +-
src/s-z/T3/T3.Series.cs | 12 +-
src/s-z/Tema/Tema.Series.cs | 12 +-
src/s-z/Tema/Tema.Utilities.cs | 2 +-
src/s-z/Tr/Tr.Series.cs | 2 +-
src/s-z/Trix/Trix.Series.cs | 10 +-
src/s-z/Trix/Trix.Utilities.cs | 2 +-
src/s-z/Tsi/Tsi.Series.cs | 28 ++--
src/s-z/UlcerIndex/UlcerIndex.Models.cs | 2 +-
src/s-z/UlcerIndex/UlcerIndex.Series.cs | 4 +-
src/s-z/Ultimate/Ultimate.Series.cs | 36 ++--
.../VolatilityStop/VolatilityStop.Series.cs | 6 +-
src/s-z/Vortex/Vortex.Series.cs | 4 +-
src/s-z/Vwap/Vwap.Series.cs | 10 +-
src/s-z/Vwma/Vwma.Series.cs | 6 +-
src/s-z/WilliamsR/WilliamsR.Series.cs | 4 +-
src/s-z/Wma/Wma.Series.cs | 4 +-
src/s-z/ZigZag/ZigZag.Models.cs | 2 +-
src/s-z/ZigZag/ZigZag.Series.cs | 95 +++++------
tests/indicators/TestBase.cs | 53 +++---
.../_common/Candles/Candles.Tests.cs | 12 +-
.../_common/Generics/Pruning.Tests.cs | 6 +-
.../indicators/_common/Generics/Seek.Tests.cs | 6 +-
.../indicators/_common/Generics/Sort.Tests.cs | 20 +--
.../_common/Generics/Transforms.Tests.cs | 2 +-
.../indicators/_common/Math/Numerix.Tests.cs | 20 +--
.../Observables/AbstractProvider.Tests.cs | 8 +-
.../_common/Observables/Cache.Management.cs | 6 +-
.../Observables/ChainProvider.Tests.cs | 8 +-
.../Observables/QuoteProvider.Tests.cs | 4 +-
.../_common/Quotes/Quote.Aggregates.Tests.cs | 23 +--
.../_common/Quotes/Quote.Converters.Tests.cs | 101 ++++++------
.../_common/Quotes/Quote.Equality.Tests.cs | 10 +-
.../_common/Quotes/Quote.Validation.Tests.cs | 22 +--
.../_common/Results/Result.Utilities.Tests.cs | 6 +-
.../_common/Use/Use.Series.Tests.cs | 26 +--
tests/indicators/_testdata/Helper.Importer.cs | 2 +-
tests/indicators/_testdata/Helper.Random.cs | 30 ++--
tests/indicators/a-d/Adl/Adl.Series.Tests.cs | 14 +-
tests/indicators/a-d/Adx/Adx.Tests.cs | 32 ++--
.../a-d/Alligator/Alligator.Series.Tests.cs | 40 ++---
.../a-d/Alligator/Alligator.Stream.Tests.cs | 12 +-
tests/indicators/a-d/Alma/Alma.Tests.cs | 38 ++---
tests/indicators/a-d/Aroon/Aroon.Tests.cs | 22 +--
tests/indicators/a-d/Atr/Atr.Tests.cs | 20 +--
tests/indicators/a-d/AtrStop/AtrStop.Tests.cs | 20 +--
tests/indicators/a-d/Awesome/Awesome.Tests.cs | 26 +--
tests/indicators/a-d/Beta/Beta.Tests.cs | 114 +++++++------
.../BollingerBands/BollingerBands.Tests.cs | 22 +--
tests/indicators/a-d/Bop/Bop.Tests.cs | 24 +--
tests/indicators/a-d/Cci/Cci.Tests.cs | 22 +--
.../a-d/ChaikinOsc/ChaikinOsc.Tests.cs | 20 +--
.../a-d/Chandelier/Chandelier.Tests.cs | 26 +--
tests/indicators/a-d/Chop/Chop.Tests.cs | 24 +--
tests/indicators/a-d/Cmf/Cmf.Tests.cs | 24 +--
tests/indicators/a-d/Cmo/Cmo.Tests.cs | 20 +--
.../a-d/ConnorsRsi/ConnorsRsi.Tests.cs | 26 +--
.../a-d/Correlation/Correlation.Tests.cs | 46 +++---
tests/indicators/a-d/Dema/Dema.Tests.cs | 20 +--
tests/indicators/a-d/Doji/Doji.Tests.cs | 18 +-
.../indicators/a-d/Donchian/Donchian.Tests.cs | 20 +--
tests/indicators/a-d/Dpo/Dpo.Tests.cs | 22 +--
tests/indicators/a-d/Dynamic/Dynamic.Tests.cs | 22 +--
.../indicators/e-k/ElderRay/ElderRay.Tests.cs | 22 +--
tests/indicators/e-k/Ema/Ema.Series.Tests.cs | 40 ++---
tests/indicators/e-k/Ema/Ema.Stream.Tests.cs | 8 +-
tests/indicators/e-k/Epma/Epma.Tests.cs | 20 +--
tests/indicators/e-k/Fcb/Fcb.Tests.cs | 20 +--
.../FisherTransform/FisherTransform.Tests.cs | 26 +--
.../e-k/ForceIndex/ForceIndex.Tests.cs | 18 +-
tests/indicators/e-k/Fractal/Fractal.Tests.cs | 18 +-
tests/indicators/e-k/Gator/Gator.Tests.cs | 20 +--
.../e-k/HeikinAshi/HeikinAshi.Tests.cs | 12 +-
tests/indicators/e-k/Hma/Hma.Tests.cs | 20 +--
.../e-k/HtTrendline/HtTrendline.Tests.cs | 18 +-
tests/indicators/e-k/Hurst/Hurst.Tests.cs | 28 ++--
.../indicators/e-k/Ichimoku/Ichimoku.Tests.cs | 24 +--
tests/indicators/e-k/Kama/Kama.Tests.cs | 42 ++---
tests/indicators/e-k/Keltner/Keltner.Tests.cs | 20 +--
tests/indicators/e-k/Kvo/Kvo.Tests.cs | 22 +--
.../m-r/MaEnvelopes/MaEnvelopes.Tests.cs | 66 ++++----
tests/indicators/m-r/Macd/Macd.Tests.cs | 24 +--
tests/indicators/m-r/Mama/Mama.Tests.cs | 24 +--
.../indicators/m-r/Marubozu/Marubozu.Tests.cs | 18 +-
tests/indicators/m-r/Mfi/Mfi.Tests.cs | 20 +--
tests/indicators/m-r/Obv/Obv.Tests.cs | 12 +-
.../m-r/ParabolicSar/ParabolicSar.Tests.cs | 24 +--
.../m-r/PivotPoints/PivotPoints.Tests.cs | 86 +++++-----
tests/indicators/m-r/Pivots/Pivots.Tests.cs | 32 ++--
tests/indicators/m-r/Pmo/Pmo.Tests.cs | 28 ++--
tests/indicators/m-r/Prs/Prs.Tests.cs | 40 ++---
tests/indicators/m-r/Pvo/Pvo.Tests.cs | 20 +--
tests/indicators/m-r/Renko/Renko.Tests.cs | 20 +--
tests/indicators/m-r/Roc/Roc.Tests.cs | 20 +--
tests/indicators/m-r/RocWb/RocWb.Tests.cs | 24 +--
.../m-r/RollingPivots/RollingPivots.Tests.cs | 84 +++++-----
tests/indicators/m-r/Rsi/Rsi.Tests.cs | 38 ++---
tests/indicators/s-z/Slope/Slope.Tests.cs | 22 +--
.../indicators/s-z/Sma/Sma.Analysis.Tests.cs | 20 +--
tests/indicators/s-z/Sma/Sma.Series.Tests.cs | 39 ++---
tests/indicators/s-z/Sma/Sma.Stream.Tests.cs | 16 +-
tests/indicators/s-z/Smi/Smi.Tests.cs | 34 ++--
tests/indicators/s-z/Smma/Smma.Tests.cs | 20 +--
.../s-z/StarcBands/StarcBands.Tests.cs | 20 +--
tests/indicators/s-z/Stc/Stc.Tests.cs | 28 ++--
tests/indicators/s-z/StdDev/StdDev.Tests.cs | 22 +--
.../StdDevChannels/StdDevChannels.Tests.cs | 28 ++--
tests/indicators/s-z/Stoch/Stoch.Tests.cs | 46 +++---
.../indicators/s-z/StochRsi/StochRsi.Tests.cs | 34 ++--
.../s-z/SuperTrend/SuperTrend.Tests.cs | 22 +--
tests/indicators/s-z/T3/T3.Tests.cs | 22 +--
tests/indicators/s-z/Tema/Tema.Tests.cs | 22 +--
tests/indicators/s-z/Tr/Tr.Tests.cs | 16 +-
tests/indicators/s-z/Trix/Trix.Tests.cs | 22 +--
tests/indicators/s-z/Tsi/Tsi.Tests.cs | 42 ++---
.../s-z/UlcerIndex/UlcerIndex.Tests.cs | 30 ++--
.../indicators/s-z/Ultimate/Ultimate.Tests.cs | 24 +--
.../VolatilityStop/VolatilityStop.Tests.cs | 20 +--
tests/indicators/s-z/Vortex/Vortex.Tests.cs | 16 +-
tests/indicators/s-z/Vwap/Vwap.Tests.cs | 28 ++--
tests/indicators/s-z/Vwma/Vwma.Tests.cs | 16 +-
.../s-z/WilliamsR/WilliamsR.Tests.cs | 29 ++--
tests/indicators/s-z/Wma/Wma.Tests.cs | 24 +--
tests/indicators/s-z/ZigZag/ZigZag.Tests.cs | 26 +--
tests/observe/Program.cs | 33 ++--
tests/other/Convergence.Tests.cs | 151 ++++++++---------
tests/other/CustomIndicator.Tests.cs | 12 +-
tests/other/PublicApi.Tests.cs | 41 ++---
tests/performance/Perf.Indicators.Series.cs | 5 +-
.../Perf.Indicators.Stream.External.cs | 1 +
tests/performance/Perf.Indicators.Stream.cs | 1 +
tests/performance/Perf.Library.Helpers.cs | 24 +--
tests/performance/Perf.Library.Internals.cs | 6 +-
.../performance/_testdata/Helper.Importer.cs | 2 +-
255 files changed, 2702 insertions(+), 2772 deletions(-)
create mode 100644 Stock.Indicators.sln.DotSettings
delete mode 100644 src/a-d/Adl/info.xml
create mode 100644 src/s-z/SmaAnalysis/Sma.Analysis.Api.cs
rename src/s-z/{Sma/Sma.Analysis.cs => SmaAnalysis/Sma.Analysis.Series.cs} (88%)
diff --git a/Stock.Indicators.sln.DotSettings b/Stock.Indicators.sln.DotSettings
new file mode 100644
index 000000000..73494bca2
--- /dev/null
+++ b/Stock.Indicators.sln.DotSettings
@@ -0,0 +1,2 @@
+
+ True
\ No newline at end of file
diff --git a/docs/pages/utilities.md b/docs/pages/utilities.md
index 40459183c..34e921c35 100644
--- a/docs/pages/utilities.md
+++ b/docs/pages/utilities.md
@@ -28,13 +28,9 @@ var results = quotes
{% include candlepart-options.md %}
-### Using tuple quotes
-
-`quotes.ToTupleCollection()` is a method for converting any `TQuote` collection to a simple [tuple](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/value-tuples) `(DateTime, double)` formatted `Collection`. Most indicators in our library will accept this tuple format. With that said, there are many indicators that also require the full OHLCV quote format, so it cannot be used universally.
-
### Sort quotes
-`quotes.ToSortedCollection()` sorts any collection of `TQuote` or tuple `(DateTime, double)` and returns it as a `Collection` sorted by ascending `Timestamp`. You do not need to sort quotes before using library indicators; however, if you are creating [custom indicators]({{site.baseurl}}/custom-indicators/#content) it's important to analyze `quotes` in a proper sequence.
+`quotes.ToSortedCollection()` sorts any collection of `TQuote` or `ISeries` and returns it as a `Collection` sorted by ascending `Timestamp`. You do not need to sort quotes before using library indicators; however, if you are creating [custom indicators]({{site.baseurl}}/custom-indicators/#content) it's important to analyze `quotes` in a proper sequence.
### Resize quote history
@@ -150,16 +146,6 @@ See [individual indicator pages]({{site.baseurl}}/indicators/#content) for infor
>
> 🚩 **Warning**: without a specified `removePeriods` value, this utility will reverse-engineer the pruning amount. When there are unusual results or when chaining multiple indicators, there will be an erroneous increase in the amount of pruning. If you want more certainty, use a specific number for `removePeriods`. Using this method on chained indicators without `removePeriods` is strongly discouraged.
-### Using tuple results
-
-`results.ToTupleCollection()` converts results to a simpler `(DateTime Timestamp, double? Value)` [tuple](https://docs.microsoft.com/dotnet/csharp/language-reference/builtin-types/value-tuples) `Collection`.
-
-`results.ToTupleNaN()` converts results to simpler `(DateTime Timestamp, double Value)` tuple `Collection` with `null` values converted to `double.NaN`.
-
-`results.ToTupleChainable()` is a specialty converter used to prepare [custom indicators]({{site.baseurl}}/custom-indicators/#content) for chaining by removing `null` warmup periods and converting all remaining `null` values to `double.NaN`.
-
-> 🚩 **Warning**: warmup periods are pruned when using `.ToTupleChainable()`, resulting in fewer records.
-
### Sort results
`results.ToSortedCollection()` sorts any collection of indicator results and returns it as a `Collection` sorted by ascending `Timestamp`. Results from the library indicators are already sorted, so you'd only potentially need this if you're creating [custom indicators]({{site.baseurl}}/custom-indicators/#content).
diff --git a/src/_common/Candles/Candles.Models.cs b/src/_common/Candles/Candles.Models.cs
index 293595f0e..691e020de 100644
--- a/src/_common/Candles/Candles.Models.cs
+++ b/src/_common/Candles/Candles.Models.cs
@@ -2,7 +2,7 @@ namespace Skender.Stock.Indicators;
// CANDLESTICK MODELS
-public readonly record struct CandleProperties : IQuote, IReusable
+public readonly record struct CandleProperties : IQuote
{
// base quote properties
public DateTime Timestamp { get; init; }
@@ -16,14 +16,14 @@ namespace Skender.Stock.Indicators;
// raw sizes
public decimal? Size => High - Low;
- public decimal? Body => (Open > Close) ? (Open - Close) : (Close - Open);
+ public decimal? Body => Open > Close ? Open - Close : Close - Open;
public decimal? UpperWick => High - (Open > Close ? Open : Close);
public decimal? LowerWick => (Open > Close ? Close : Open) - Low;
// percent sizes
- public double? BodyPct => (Size != 0) ? (double?)(Body / Size) : 1;
- public double? UpperWickPct => (Size != 0) ? (double?)(UpperWick / Size) : 1;
- public double? LowerWickPct => (Size != 0) ? (double?)(LowerWick / Size) : 1;
+ public double? BodyPct => Size != 0 ? (double?)(Body / Size) : 1;
+ public double? UpperWickPct => Size != 0 ? (double?)(UpperWick / Size) : 1;
+ public double? LowerWickPct => Size != 0 ? (double?)(LowerWick / Size) : 1;
// directional info
public bool IsBullish => Close > Open;
diff --git a/src/_common/Candles/Candles.Utilities.cs b/src/_common/Candles/Candles.Utilities.cs
index aab413d36..f6f29ad03 100644
--- a/src/_common/Candles/Candles.Utilities.cs
+++ b/src/_common/Candles/Candles.Utilities.cs
@@ -30,7 +30,7 @@ public static IEnumerable ToCandles(
internal static List ToCandleResults(
this IEnumerable quotes)
where TQuote : IQuote => quotes
- .Select(q => new CandleResult() {
+ .Select(q => new CandleResult {
Timestamp = q.Timestamp,
Match = Match.None,
Candle = q.ToCandle()
diff --git a/src/_common/Enums.cs b/src/_common/Enums.cs
index 403ab7d10..8e4b32356 100644
--- a/src/_common/Enums.cs
+++ b/src/_common/Enums.cs
@@ -8,7 +8,7 @@ namespace Skender.Stock.Indicators;
///
public enum Act
{
- AddNew,
+ AddNew = 0, // default
AddOld,
Update,
Delete,
@@ -20,16 +20,16 @@ public enum Act
///
public enum CandlePart
{
+ Close = 0, // default
Open,
High,
Low,
- Close,
Volume,
- HL2,
- HLC3,
- OC2,
- OHL3,
- OHLC4
+ Hl2,
+ Hlc3,
+ Oc2,
+ Ohl3,
+ Ohlc4
}
///
@@ -37,7 +37,7 @@ public enum CandlePart
///
public enum EndType
{
- Close = 0,
+ Close = 0, // default
HighLow = 1
}
@@ -50,7 +50,7 @@ public enum Match
BullSignal = 100,
BullBasis = 10,
Neutral = 1,
- None = 0,
+ None = 0, // default
BearBasis = -10,
BearSignal = -100,
BearConfirmed = -200
@@ -61,17 +61,17 @@ public enum Match
///
public enum MaType
{
- ALMA,
- DEMA,
- EPMA,
- EMA,
- HMA,
- KAMA,
- MAMA,
- SMA,
- SMMA,
- TEMA,
- WMA
+ Sma = 0, // default
+ Alma,
+ Dema,
+ Epma,
+ Ema,
+ Hma,
+ Kama,
+ Mama,
+ Smma,
+ Tema,
+ Wma
}
///
@@ -80,9 +80,9 @@ public enum MaType
///
public enum PeriodSize
{
- Month,
+ Day = 0, // default
Week,
- Day,
+ Month,
FourHours,
TwoHours,
OneHour,
diff --git a/src/_common/Generics/Pruning.cs b/src/_common/Generics/Pruning.cs
index ffee2082f..125cdec83 100644
--- a/src/_common/Generics/Pruning.cs
+++ b/src/_common/Generics/Pruning.cs
@@ -23,17 +23,17 @@ internal static List Remove(
{
return [];
}
- else
- {
- if (removePeriods > 0)
- {
- for (int i = 0; i < removePeriods; i++)
- {
- seriesList.RemoveAt(0);
- }
- }
+ if (removePeriods <= 0)
+ {
return seriesList;
}
+
+ for (int i = 0; i < removePeriods; i++)
+ {
+ seriesList.RemoveAt(0);
+ }
+
+ return seriesList;
}
}
diff --git a/src/_common/Generics/Seek.cs b/src/_common/Generics/Seek.cs
index 92dd645df..70727d940 100644
--- a/src/_common/Generics/Seek.cs
+++ b/src/_common/Generics/Seek.cs
@@ -17,20 +17,19 @@ public static class Seeking
///
/// Sequence contains no matching element
///
- public static TSeries? Find(
+ public static TSeries Find(
this IEnumerable series,
DateTime lookupDate)
- where TSeries : ISeries => series
- .First(x => x.Timestamp == lookupDate);
+ where TSeries : ISeries
+ => series.First(x => x.Timestamp == lookupDate);
// TODO: add TryFind(), like TryParse() since struct won't allow null return types.
// May just use this (above) with a try/catch and `bool` primary return type.
// FIND INDEX by DATE
public static int FindIndex(
- this List series,
+ this List? series,
DateTime lookupDate)
- where TSeries : ISeries => series == null
- ? -1
- : series.FindIndex(x => x.Timestamp == lookupDate);
+ where TSeries : ISeries
+ => series?.FindIndex(x => x.Timestamp == lookupDate) ?? -1;
}
diff --git a/src/_common/Math/NullMath.cs b/src/_common/Math/NullMath.cs
index 839b3da92..19f483a9c 100644
--- a/src/_common/Math/NullMath.cs
+++ b/src/_common/Math/NullMath.cs
@@ -7,17 +7,17 @@ namespace Skender.Stock.Indicators;
public static class NullMath
{
public static double? Abs(this double? value)
- => (value is null)
+ => value is null
? null
: value < 0 ? (double)-value : (double)value;
public static decimal? Round(this decimal? value, int digits)
- => (value is null)
+ => value is null
? null
: Math.Round((decimal)value, digits);
public static double? Round(this double? value, int digits)
- => (value is null)
+ => value is null
? null
: Math.Round((double)value, digits);
@@ -31,12 +31,12 @@ public static double Null2NaN(this double? value)
=> value ?? double.NaN;
public static double Null2NaN(this decimal? value)
- => (value is null)
+ => value is null
? double.NaN
: (double)value;
public static double? NaN2Null(this double? value)
- => (value is not null and double.NaN)
+ => value is double.NaN
? null
: value;
diff --git a/src/_common/Math/Numerix.cs b/src/_common/Math/Numerix.cs
index b41698b0b..14d2bd607 100644
--- a/src/_common/Math/Numerix.cs
+++ b/src/_common/Math/Numerix.cs
@@ -13,26 +13,28 @@ public static double StdDev(this double[] values)
double sd = 0;
int n = values.Length;
- if (n > 1)
+ if (n <= 1)
{
- double sum = 0;
- for (int i = 0; i < n; i++)
- {
- sum += values[i];
- }
-
- double avg = sum / n;
-
- double sumSq = 0;
- for (int i = 0; i < n; i++)
- {
- double v = values[i];
- sumSq += (v - avg) * (v - avg);
- }
-
- sd = Math.Sqrt(sumSq / n);
+ return sd;
}
+ double sum = 0;
+ for (int i = 0; i < n; i++)
+ {
+ sum += values[i];
+ }
+
+ double avg = sum / n;
+
+ double sumSq = 0;
+ for (int i = 0; i < n; i++)
+ {
+ double v = values[i];
+ sumSq += (v - avg) * (v - avg);
+ }
+
+ sd = Math.Sqrt(sumSq / n);
+
return sd;
}
diff --git a/src/_common/Observables/AbstractCache.cs b/src/_common/Observables/AbstractCache.cs
index 7b2ce7c53..788646587 100644
--- a/src/_common/Observables/AbstractCache.cs
+++ b/src/_common/Observables/AbstractCache.cs
@@ -8,8 +8,6 @@ namespace Skender.Stock.Indicators;
public abstract class AbstractCache : IStreamCache
where TSeries : struct, ISeries
{
- #region CONSTRUCTORS
-
///
/// Default. Use internal cache.
///
@@ -17,81 +15,17 @@ protected AbstractCache()
{
Cache = [];
}
- #endregion
-
- # region PROPERTIES
public IReadOnlyList Results => Cache;
public bool IsFaulted { get; private set; }
- internal List Cache { get; private set; }
+ internal List Cache { get; }
- private TSeries LastArrival { get; set; } = new();
+ private TSeries LastArrival { get; set; }
private int OverflowCount { get; set; }
- #endregion
-
- #region METHODS (UTILITIES)
-
- // get the cache index based on a timestamp
- ///
- public int FindIndex(DateTime timeStamp)
- => Cache.FindIndex(x => x.Timestamp == timeStamp);
- // get a segment of the cache
- ///
- public IReadOnlyList GetRange(int index, int count)
- => Cache.GetRange(index, count);
- #endregion
-
- #region METHODS (CLEAR CACHE)
-
- // clear entire cache without restore
- ///
- public void ClearCache()
- {
- // nothing to do
- if (Cache.Count == 0)
- {
- Cache = [];
- return;
- }
-
- // reset all (with handling)
- ClearCache(0);
- }
-
- ///
- public void ClearCache(DateTime fromTimestamp)
- {
- // start of range
- int s = Cache
- .FindIndex(c => c.Timestamp >= fromTimestamp);
-
- // something to do
- if (s != -1)
- {
- ClearCache(s);
- }
- }
-
- ///
- public void ClearCache(int fromIndex)
- => ClearCache(fromIndex, toIndex: Cache.Count - 1);
-
- ///
- /// Deletes cache entries between index range values.
- ///
- ///
- /// This is overridden/implemented in inheriting class
- /// due to unique requirement to notify subscribers.
- ///
- /// First element to delete
- /// Last element to delete
- protected abstract void ClearCache(
- int fromIndex, int? toIndex = null);
- #endregion
#region METHODS (CACHE MANAGEMENT)
@@ -111,14 +45,13 @@ protected Act CacheWithAnalysis(TSeries item)
if (CheckOverflow(item) is Act.DoNothing)
{
return Act.DoNothing;
- };
+ }
// DETERMINE ACTion INSTRUCTION
Act act;
- List cache = Cache;
- int length = cache.Count;
+ int length = Cache.Count;
// first
if (length == 0)
@@ -127,7 +60,7 @@ protected Act CacheWithAnalysis(TSeries item)
return ModifyCache(act, item);
}
- TSeries last = cache[length - 1];
+ TSeries last = Cache[length - 1];
// newer
if (item.Timestamp > last.Timestamp)
@@ -139,7 +72,7 @@ protected Act CacheWithAnalysis(TSeries item)
else
{
// seek duplicate
- int foundIndex = cache
+ int foundIndex = Cache
.FindIndex(x => x.Timestamp == item.Timestamp);
// replace duplicate
@@ -166,7 +99,7 @@ protected Act PurgeWithAnalysis(TSeries item)
if (CheckOverflow(item) is Act.DoNothing)
{
return Act.DoNothing;
- };
+ }
// determine if record exists
int foundIndex = Cache
@@ -314,11 +247,11 @@ protected Act ModifyCache(Act act, TSeries item)
if (OverflowCount > 100)
{
- string msg = """
- A repeated stream update exceeded the 100 attempt threshold.
- Check and remove circular chains or check your stream provider.
- Provider terminated.
- """;
+ const string msg = """
+ A repeated stream update exceeded the 100 attempt threshold.
+ Check and remove circular chains or check your stream provider.
+ Provider terminated.
+ """;
IsFaulted = true;
@@ -353,4 +286,46 @@ Provider terminated.
return act;
}
#endregion
+
+ #region METHODS (UTILITIES)
+
+ // get the cache index based on a timestamp
+ ///
+ public int FindIndex(DateTime timeStamp)
+ => Cache.FindIndex(x => x.Timestamp == timeStamp);
+
+ // clear entire cache without restore
+ ///
+ public void ClearCache() => ClearCache(0);
+
+ ///
+ public void ClearCache(DateTime fromTimestamp)
+ {
+ // start of range
+ int fromIndex = Cache
+ .FindIndex(c => c.Timestamp >= fromTimestamp);
+
+ // something to do
+ if (fromIndex != -1)
+ {
+ ClearCache(fromIndex);
+ }
+ }
+
+ ///
+ public void ClearCache(int fromIndex)
+ => ClearCache(fromIndex, toIndex: Cache.Count - 1);
+
+ ///
+ /// Deletes cache entries between index range values.
+ ///
+ ///
+ /// This is implemented in inheriting (provider) class
+ /// due to unique requirement to notify subscribers.
+ ///
+ /// First element to delete
+ /// Last element to delete
+ protected abstract void ClearCache(
+ int fromIndex, int toIndex);
+ #endregion
}
diff --git a/src/_common/Observables/AbstractChainInChainOut.cs b/src/_common/Observables/AbstractChainInChainOut.cs
index bf7314d60..d54976c61 100644
--- a/src/_common/Observables/AbstractChainInChainOut.cs
+++ b/src/_common/Observables/AbstractChainInChainOut.cs
@@ -7,25 +7,20 @@ public abstract class AbstractChainInChainOut
{
// observer members only
- #region CONSTRUCTORS
-
internal AbstractChainInChainOut(
IChainProvider provider)
{
Provider = provider;
}
- #endregion
-
- #region PROPERTIES
- public IChainProvider Provider { get; private set; }
+ public IChainProvider Provider { get; }
public bool IsSubscribed => Subscription is not null;
protected IDisposable? Subscription { get; set; }
protected IReadOnlyList ProviderCache => Provider.Results;
- #endregion
+
# region METHODS (OBSERVER)
@@ -41,20 +36,18 @@ public void OnNext((Act, TIn) value)
public void Unsubscribe() => Subscription?.Dispose();
#endregion
- #region METHODS (UTILITIES)
+ #region METHODS (CACHE UTILITIES)
- // restart subscription
+ /// full reset
+ ///
public void Reinitialize()
{
Unsubscribe();
ClearCache();
-
Subscription = Provider.Subscribe(this);
}
- // rebuild cache
- public void RebuildCache() => RebuildCache(0);
-
+ /// build cache from timestamp
///
public void RebuildCache(
DateTime fromTimestamp)
@@ -68,16 +61,12 @@ public void RebuildCache(
}
}
+ /// rebuild cache from index
///
public void RebuildCache(int fromIndex)
- => RebuildCache(fromIndex, toIndex: Cache.Count - 1);
-
- // rebuild cache from index
- protected override void RebuildCache(
- int fromIndex, int? toIndex = null)
{
- ClearCache(fromIndex, toIndex);
- Provider.Resend(this, fromIndex, toIndex);
+ ClearCache(fromIndex);
+ Provider.Resend(this, fromIndex);
}
#endregion
}
diff --git a/src/_common/Observables/AbstractChainInResultOut.cs b/src/_common/Observables/AbstractChainInResultOut.cs
index f8b6ee81b..568cac358 100644
--- a/src/_common/Observables/AbstractChainInResultOut.cs
+++ b/src/_common/Observables/AbstractChainInResultOut.cs
@@ -7,25 +7,20 @@ public abstract class AbstractChainInResultOut
{
// observer members only
- #region CONSTRUCTORS
-
internal AbstractChainInResultOut(
IChainProvider provider)
{
Provider = provider;
}
- #endregion
-
- #region PROPERTIES
- public IChainProvider Provider { get; private set; }
+ public IChainProvider Provider { get; }
public bool IsSubscribed => Subscription is not null;
protected IDisposable? Subscription { get; set; }
protected IReadOnlyList ProviderCache => Provider.Results;
- #endregion
+
# region METHODS (OBSERVER)
@@ -41,20 +36,18 @@ public void OnNext((Act, TIn) value)
public void Unsubscribe() => Subscription?.Dispose();
#endregion
- #region METHODS (UTILITIES)
+ #region METHODS (CACHE UTILITIES)
- // restart subscription
+ /// full reset
+ ///
public void Reinitialize()
{
Unsubscribe();
ClearCache();
-
Subscription = Provider.Subscribe(this);
}
- // rebuild cache
- public void RebuildCache() => RebuildCache(0);
-
+ /// build cache from timestamp
///
public void RebuildCache(
DateTime fromTimestamp)
@@ -68,16 +61,12 @@ public void RebuildCache(
}
}
+ /// rebuild cache from index
///
public void RebuildCache(int fromIndex)
- => RebuildCache(fromIndex, toIndex: Cache.Count - 1);
-
- // rebuild cache from index
- protected override void RebuildCache(
- int fromIndex, int? toIndex = null)
{
- ClearCache(fromIndex, toIndex);
- Provider.Resend(this, fromIndex, toIndex);
+ ClearCache(fromIndex);
+ Provider.Resend(this, fromIndex);
}
#endregion
}
diff --git a/src/_common/Observables/AbstractProvider.cs b/src/_common/Observables/AbstractProvider.cs
index aa7a8776b..1cb97e11a 100644
--- a/src/_common/Observables/AbstractProvider.cs
+++ b/src/_common/Observables/AbstractProvider.cs
@@ -1,34 +1,7 @@
namespace Skender.Stock.Indicators;
// STREAM PROVIDERS (BASE)
-
-#region interface variants
-///
-/// Quote provider (abstract base)
-///
-public abstract class AbstractQuoteProvider
- : AbstractProvider, IQuoteProvider, IChainProvider
- where TQuote : struct, IQuote, IReusable
-{
- // string label
- public override string ToString()
- => $"{Cache.Count} quotes (type: {nameof(TQuote)})";
-}
-
-///
-/// Chainable result provider (abstract base)
-///
-public abstract class AbstractChainProvider
- : AbstractProvider, IChainProvider
- where TReusableResult : struct, IReusable;
-
-///
-/// Non-chainable result provider (abstract base)
-///
-public abstract class AbstractResultProvider
- : AbstractProvider, IResultProvider
- where TResult : struct, IResult;
-#endregion
+// with Quote, Chain, Result variants (at bottom)
///
/// Streaming provider (abstract base)
@@ -39,26 +12,20 @@ public abstract class AbstractProvider
{
// provider members only
- # region FIELDS & PROPERTIES
-
- // fields
+ private readonly HashSet> _observers = [];
- private readonly HashSet> Observers = new();
+ public bool HasSubscribers => _observers.Count > 0;
- // properties
+ public int SubscriberCount => _observers.Count;
- public bool HasSubscribers => Observers.Count > 0;
-
- public int SubscriberCount => Observers.Count;
- #endregion
# region METHODS (OBSERVABLE)
// subscribe observer
public IDisposable Subscribe(IObserver<(Act, TSeries)> observer)
{
- Observers.Add(observer);
- Subscription sub = new(Observers, observer);
+ _observers.Add(observer);
+ Subscription sub = new(_observers, observer);
Resend(observer, act: Act.AddNew, fromIndex: 0); // catch-up new guy
return sub;
}
@@ -66,22 +33,22 @@ public IDisposable Subscribe(IObserver<(Act, TSeries)> observer)
// unsubscribe all observers
public void EndTransmission()
{
- foreach (IObserver<(Act, TSeries)> obs in Observers.ToArray())
+ foreach (IObserver<(Act, TSeries)> obs in _observers.ToArray())
{
- if (Observers.Contains(obs))
+ if (_observers.Contains(obs))
{
obs.OnCompleted();
}
}
- Observers.Clear();
+ _observers.Clear();
}
///
- /// Sends new item to all subscribers
+ /// Sends TSeries item to all subscribers
///
- ///
- ///
+ /// Caching instruction
+ /// TSeries item to send
protected void NotifyObservers(Act act, TSeries item)
{
// do not propogate "do nothing" acts
@@ -91,11 +58,10 @@ protected void NotifyObservers(Act act, TSeries item)
}
// send to subscribers
- List> obsList = [.. Observers];
+ List> obsList = [.. _observers];
- for (int i = 0; i < obsList.Count; i++)
+ foreach (IObserver<(Act, TSeries)> obs in obsList)
{
- IObserver<(Act, TSeries)> obs = obsList[i];
obs.OnNext((act, item));
}
}
@@ -121,9 +87,10 @@ private class Subscription(
#region METHODS (UTILITIES)
- // string label
+ /// string label
public abstract override string ToString();
+ /// resend newer to an observer (from timestamp)
///
public void Resend(
IObserver<(Act, TSeries)> toObserver,
@@ -141,42 +108,54 @@ public void Resend(
Resend(toObserver, fromIndex);
}
- // resend to an observer
+ /// resend newer to an observer (from index)
+ ///
+ public void Resend(
+ IObserver<(Act, TSeries)> toObserver,
+ int fromIndex)
+ => Resend(toObserver, fromIndex, Cache.Count - 1);
+
+ /// resends values in a range to a requesting observer
///
public void Resend(
IObserver<(Act, TSeries)> toObserver,
int fromIndex,
- int? toIndex = null)
- => Resend(toObserver, fromIndex, default, toIndex);
+ int toIndex)
+ => Resend(toObserver, Act.AddOld, fromIndex, toIndex);
- // resend to an observer (defined Act)
+ ///
+ /// Resends values in a range to a requesting observer,
+ /// between the provided indexes (inclusive), with a specific act.
+ ///
+ /// Subscription identity
+ /// Starting index, inclusive
+ /// Ending index, inclusive
+ /// Caching instruction
private void Resend(
IObserver<(Act, TSeries)> toObserver,
- int fromIndex,
Act act,
+ int fromIndex,
int? toIndex = null)
{
- if (toObserver is not null && Observers.Contains(toObserver))
+ if (toObserver is null || !_observers.Contains(toObserver))
{
- // determine start/end of range
- int fr = Math.Max(0, fromIndex);
- int to = Math.Min(toIndex ?? Cache.Count, Cache.Count);
+ return;
+ }
- for (int i = fr; i < to; i++)
- {
- toObserver.OnNext((act, Cache[i]));
- }
+ // determine start/end of range
+ int fr = Math.Max(0, fromIndex);
+ int to = Math.Min(toIndex ?? Cache.Count, Cache.Count);
+
+ for (int i = fr; i < to; i++)
+ {
+ toObserver.OnNext((act, Cache[i]));
}
}
- // clears cache segment
+ /// clears cache segment
///
- ///
- /// Since upstream allows +/- offset, the arguments
- /// need to be evaluated to determine start/end of range.
- ///
protected override void ClearCache(
- int fromIndex, int? toIndex = null)
+ int fromIndex, int toIndex)
{
if (Cache.Count is 0)
{
@@ -185,7 +164,7 @@ protected override void ClearCache(
// determine start/end of range
int fr = Math.Max(fromIndex, 0);
- int to = Math.Min(toIndex ?? Cache.Count - 1, Cache.Count - 1);
+ int to = Math.Min(toIndex, Cache.Count - 1);
// delete and deliver instruction in reverse
// order to prevent recursive recompositions
@@ -196,13 +175,34 @@ protected override void ClearCache(
NotifyObservers(act, r);
}
}
-
- ///
- /// Rebuild cache from provider.
- ///
- /// start position
- /// stop position
- protected abstract void RebuildCache(
- int fromIndex, int? toIndex = null);
#endregion
}
+
+#region QUOTE, CHAIN, RESULT PROVIDERS
+
+///
+/// Quote provider (abstract base)
+///
+public abstract class AbstractQuoteProvider
+ : AbstractProvider, IQuoteProvider, IChainProvider
+ where TQuote : struct, IQuote, IReusable
+{
+ // string label
+ public override string ToString()
+ => $"{Cache.Count} quotes (type: {nameof(TQuote)})";
+}
+
+///
+/// Chainable result provider (abstract base)
+///
+public abstract class AbstractChainProvider
+ : AbstractProvider, IChainProvider
+ where TReusableResult : struct, IReusable;
+
+///
+/// Non-chainable result provider (abstract base)
+///
+public abstract class AbstractResultProvider
+ : AbstractProvider, IResultProvider
+ where TResult : struct, IResult;
+#endregion
diff --git a/src/_common/Observables/AbstractQuoteInChainOut.cs b/src/_common/Observables/AbstractQuoteInChainOut.cs
index ada0053da..d6883e1a7 100644
--- a/src/_common/Observables/AbstractQuoteInChainOut.cs
+++ b/src/_common/Observables/AbstractQuoteInChainOut.cs
@@ -7,25 +7,20 @@ public abstract class AbstractQuoteInChainOut
{
// observer members only
- #region CONSTRUCTORS
-
internal AbstractQuoteInChainOut(
IQuoteProvider provider)
{
Provider = provider;
}
- #endregion
-
- # region PROPERTIES
- public IQuoteProvider Provider { get; private set; }
+ public IQuoteProvider Provider { get; }
public bool IsSubscribed => Subscription is not null;
protected IDisposable? Subscription { get; set; }
protected IReadOnlyList ProviderCache => Provider.Results;
- #endregion
+
# region METHODS (OBSERVER)
@@ -41,20 +36,18 @@ public void OnNext((Act, TIn) value)
public void Unsubscribe() => Subscription?.Dispose();
#endregion
- #region METHODS (UTILITIES)
+ #region METHODS (CACHE UTILITIES)
- // restart subscription
+ /// full reset
+ ///
public void Reinitialize()
{
Unsubscribe();
ClearCache();
-
Subscription = Provider.Subscribe(this);
}
- // rebuild cache
- public void RebuildCache() => RebuildCache(0);
-
+ /// build cache from timestamp
///
public void RebuildCache(
DateTime fromTimestamp)
@@ -68,16 +61,12 @@ public void RebuildCache(
}
}
+ /// rebuild cache from index
///
public void RebuildCache(int fromIndex)
- => RebuildCache(fromIndex, toIndex: Cache.Count - 1);
-
- // rebuild cache from index
- protected override void RebuildCache(
- int fromIndex, int? toIndex = null)
{
- ClearCache(fromIndex, toIndex);
- Provider.Resend(this, fromIndex, toIndex);
+ ClearCache(fromIndex);
+ Provider.Resend(this, fromIndex);
}
#endregion
}
diff --git a/src/_common/Observables/AbstractQuoteInQuoteOut.cs b/src/_common/Observables/AbstractQuoteInQuoteOut.cs
index 9b850f738..e56f4be33 100644
--- a/src/_common/Observables/AbstractQuoteInQuoteOut.cs
+++ b/src/_common/Observables/AbstractQuoteInQuoteOut.cs
@@ -10,25 +10,20 @@ public abstract class AbstractQuoteInQuoteOut
{
// observer members only
- #region CONSTRUCTORS
-
internal AbstractQuoteInQuoteOut(
IQuoteProvider provider)
{
Provider = provider;
}
- #endregion
-
- # region PROPERTIES
- public IQuoteProvider Provider { get; private set; }
+ public IQuoteProvider Provider { get; }
public bool IsSubscribed => Subscription is not null;
protected IDisposable? Subscription { get; set; }
protected IReadOnlyList ProviderCache => Provider.Results;
- #endregion
+
# region METHODS (OBSERVER)
@@ -42,19 +37,20 @@ public void OnNext((Act, TIn) value)
public void OnCompleted() => Unsubscribe();
public void Unsubscribe() => Subscription?.Dispose();
+ #endregion
- // restart subscription
+ #region METHODS (CACHE UTILITIES)
+
+ /// full reset
+ ///
public void Reinitialize()
{
Unsubscribe();
ClearCache();
-
Subscription = Provider.Subscribe(this);
}
- // rebuild cache
- public void RebuildCache() => RebuildCache(0);
-
+ /// build cache from timestamp
///
public void RebuildCache(
DateTime fromTimestamp)
@@ -68,16 +64,12 @@ public void RebuildCache(
}
}
+ /// rebuild cache from index
///
public void RebuildCache(int fromIndex)
- => RebuildCache(fromIndex, toIndex: Cache.Count - 1);
-
- // rebuild cache from index
- protected override void RebuildCache(
- int fromIndex, int? toIndex = null)
{
- ClearCache(fromIndex, toIndex);
- Provider.Resend(this, fromIndex, toIndex);
+ ClearCache(fromIndex);
+ Provider.Resend(this, fromIndex);
}
#endregion
}
diff --git a/src/_common/Observables/AbstractQuoteInResultOut.cs b/src/_common/Observables/AbstractQuoteInResultOut.cs
index 6345c4c58..c632c0441 100644
--- a/src/_common/Observables/AbstractQuoteInResultOut.cs
+++ b/src/_common/Observables/AbstractQuoteInResultOut.cs
@@ -9,25 +9,20 @@ public abstract class AbstractQuoteInResultOut
{
// observer members only
- #region CONSTRUCTORS
-
internal AbstractQuoteInResultOut(
IQuoteProvider provider)
{
Provider = provider;
}
- #endregion
-
- # region PROPERTIES
- public IQuoteProvider Provider { get; private set; }
+ public IQuoteProvider Provider { get; }
public bool IsSubscribed => Subscription is not null;
protected IDisposable? Subscription { get; set; }
protected IReadOnlyList ProviderCache => Provider.Results;
- #endregion
+
# region METHODS (OBSERVER)
@@ -43,20 +38,18 @@ public void OnNext((Act, TIn) value)
public void Unsubscribe() => Subscription?.Dispose();
#endregion
- #region METHODS (UTILITIES)
+ #region METHODS (CACHE UTILITIES)
- // restart subscription
+ /// full reset
+ ///
public void Reinitialize()
{
Unsubscribe();
ClearCache();
-
Subscription = Provider.Subscribe(this);
}
- // rebuild cache
- public void RebuildCache() => RebuildCache(0);
-
+ /// build cache from timestamp
///
public void RebuildCache(
DateTime fromTimestamp)
@@ -70,16 +63,12 @@ public void RebuildCache(
}
}
+ /// rebuild cache from index
///
public void RebuildCache(int fromIndex)
- => RebuildCache(fromIndex, toIndex: Cache.Count - 1);
-
- // rebuild cache from index
- protected override void RebuildCache(
- int fromIndex, int? toIndex = null)
{
- ClearCache(fromIndex, toIndex);
- Provider.Resend(this, fromIndex, toIndex);
+ ClearCache(fromIndex);
+ Provider.Resend(this, fromIndex);
}
#endregion
}
diff --git a/src/_common/Observables/IStreamCache.cs b/src/_common/Observables/IStreamCache.cs
index b3e160ef2..43f934550 100644
--- a/src/_common/Observables/IStreamCache.cs
+++ b/src/_common/Observables/IStreamCache.cs
@@ -5,7 +5,7 @@ namespace Skender.Stock.Indicators;
///
/// Cache of stored values and related management
///
-public interface IStreamCache
+public interface IStreamCache
where TSeries : struct, ISeries
{
///
@@ -26,12 +26,6 @@ public interface IStreamCache
/// Index value or -1 when not found
int FindIndex(DateTime timeStamp);
- ///
- /// Get a segment (window) of cached values.
- ///
- ///
- IReadOnlyList GetRange(int index, int count); // TODO: is this used?
-
///
/// Deletes all cached time-series records,
/// without restore. When applicable,
@@ -41,7 +35,7 @@ public interface IStreamCache
/// For observers, if your intention is to rebuild from a provider,
/// use alternate .
///
- void ClearCache();
+ void ClearCache() => ClearCache(0);
///
/// Deletes newer cached records from point in time,
diff --git a/src/_common/Observables/IStreamObserver.cs b/src/_common/Observables/IStreamObserver.cs
index bb6927cd7..8a34b15d1 100644
--- a/src/_common/Observables/IStreamObserver.cs
+++ b/src/_common/Observables/IStreamObserver.cs
@@ -3,25 +3,46 @@ namespace Skender.Stock.Indicators;
// STREAM OBSERVER INTERFACES
///
-/// Observer of a streamed quote source
+/// Observer of a streamed quote source.
///
+///
+/// This is used internal to the library,
+/// but can be implemented to build your own observers.
+///
///
public interface IQuoteObserver : IStreamObserver, IObserver<(Act act, TQuote quote)>
- where TQuote : struct, IQuote;
+ where TQuote : struct, IQuote
+{
+ IQuoteProvider Provider { get; }
+}
///
-/// Observer of a streamed chain source
+/// Observer of a streamed chain source.
///
-///
-public interface IChainObserver : IStreamObserver, IObserver<(Act act, TResult result)>
- where TResult : struct, IReusable;
+///
+/// This is used internal to the library,
+/// but can be implemented to build your own observers.
+///
+///
+public interface IChainObserver : IStreamObserver, IObserver<(Act act, TReusable result)>
+ where TReusable : struct, IReusable
+{
+ IChainProvider Provider { get; }
+}
///
-/// Observer of a unchainable result source
+/// Observer of a unchainable result source.
///
+///
+/// This is not used internally by the library,
+/// but can be implemented to build your own observers.
+///
///
public interface IResultObserver : IStreamObserver, IObserver<(Act act, TResult result)>
- where TResult : struct, IResult;
+ where TResult : struct, IResult
+{
+ IResultProvider Provider { get; }
+}
///
/// Observer of streamed chain or quote sources
@@ -42,7 +63,7 @@ public interface IStreamObserver
/// Full reset of the provider subscription.
///
/// This unsubscribes from the provider,
- /// clears cache, cascading deletes to subscribers,
+ /// clears cache, cascades deletes to subscribers,
/// then re-subscribes to the provider (with rebuild).
///
///
@@ -57,11 +78,11 @@ public interface IStreamObserver
/// This is different from .
/// It does not reset the provider subscription.
///
- void RebuildCache();
+ void RebuildCache() => RebuildCache(0);
///
- /// Reset the entire results cache from a known point in time
- /// and rebuild it from provider sources,
+ /// Reset the entire results cache from a point in time
+ /// and rebuilds it from provider sources,
/// with cascading updates to subscribers.
///
///
@@ -71,8 +92,8 @@ public interface IStreamObserver
void RebuildCache(DateTime fromTimestamp);
///
- /// Reset the entire results cache from a known index position
- /// and rebuild it from provider sources,
+ /// Reset the entire results cache from an index position
+ /// and rebuilds it from provider sources,
/// with cascading updates to subscribers.
///
///
diff --git a/src/_common/Observables/IStreamProvider.cs b/src/_common/Observables/IStreamProvider.cs
index d7f79eb29..f1e9c5fc2 100644
--- a/src/_common/Observables/IStreamProvider.cs
+++ b/src/_common/Observables/IStreamProvider.cs
@@ -1,27 +1,7 @@
namespace Skender.Stock.Indicators;
// STREAM OBSERVABLE INTERFACES (PROVIDERS)
-
-///
-/// Quote provider interface (observable)
-///
-///
-public interface IQuoteProvider : IStreamProvider
- where TQuote : struct, IQuote;
-
-///
-/// Chainable provider interface (observable)
-///
-///
-public interface IChainProvider : IStreamProvider
- where TResult : struct, IReusable;
-
-///
-/// Non-chainable provider interface (observable)
-///
-///
-public interface IResultProvider : IStreamProvider
- where TResult : struct, IResult;
+// with Quote, Chain, Result variants (at bottom)
///
/// Streaming provider interface (observable)
@@ -46,10 +26,10 @@ public interface IStreamProvider : IObservable<(Act, TSeries)>
IReadOnlyList Results { get; }
///
- /// Returns a short formatted label
+ /// Returns a short text label
/// with parameter values, e.g. EMA(10)
///
- /// Indicator or quote label
+ /// String label
string ToString();
///
@@ -58,33 +38,65 @@ public interface IStreamProvider : IObservable<(Act, TSeries)>
void EndTransmission();
///
- /// Finds the index position in the cache, of the provided timestamp
+ /// Finds cache index position of the provided timestamp
///
///
/// Index value or -1 when not found
int FindIndex(DateTime timeStamp);
///
- /// Resends historical cached values to a requesting observer,
+ /// Resends all newer values to a requesting observer,
/// starting from a specific timestamp.
///
- /// Subscriber identity.
- /// First period to resend.
+ /// Subscribtion identity
+ /// From timestamp, inclusive
void Resend(
IObserver<(Act, TSeries)> toObserver,
DateTime fromTimestamp);
///
- /// Resends historical cached values to a requesting observer,
+ /// Resends all newer values to a requesting observer,
/// starting at an index position.
///
- /// Subscriber identity.
- /// First periods to resend.
- ///
- /// The last period to include, or all (default).
- ///
+ /// Subscribtion identity
+ /// From index, inclusive
+ void Resend(
+ IObserver<(Act, TSeries)> toObserver,
+ int fromIndex);
+
+ ///
+ /// Resends all values in a range to a requesting observer,
+ /// starting and ending at an index position.
+ ///
+ /// Subscribtion identity
+ /// Starting index, inclusive
+ /// Ending index, inclusive
void Resend(
IObserver<(Act, TSeries)> toObserver,
int fromIndex,
- int? toIndex = null);
+ int toIndex);
}
+
+#region QUOTE, CHAIN, RESULT PROVIDERS
+
+///
+/// Quote provider interface (observable)
+///
+///
+public interface IQuoteProvider : IStreamProvider
+ where TQuote : struct, IQuote;
+
+///
+/// Chainable provider interface (observable)
+///
+///
+public interface IChainProvider : IStreamProvider
+ where TResult : struct, IReusable;
+
+///
+/// Non-chainable provider interface (observable)
+///
+///
+public interface IResultProvider : IStreamProvider
+ where TResult : struct, IResult;
+#endregion
diff --git a/src/_common/Observables/QuoteProvider.cs b/src/_common/Observables/QuoteProvider.cs
index d7e475d0a..7f459aea4 100644
--- a/src/_common/Observables/QuoteProvider.cs
+++ b/src/_common/Observables/QuoteProvider.cs
@@ -43,12 +43,9 @@ public Act Add(TQuote quote)
///
public void Add(IEnumerable quotes)
{
- List added = quotes
- .ToSortedList();
-
- for (int i = 0; i < added.Count; i++)
+ foreach (TQuote quote in quotes.ToSortedList())
{
- Add(added[i]);
+ Add(quote);
}
}
@@ -72,8 +69,4 @@ public Act Delete(TQuote quote)
throw;
}
}
-
- protected override void RebuildCache(
- int fromIndex, int? toIndex = null)
- => throw new InvalidOperationException("Does not apply.");
}
diff --git a/src/_common/ObsoleteV3.cs b/src/_common/ObsoleteV3.cs
index 7ed058b1a..639997250 100644
--- a/src/_common/ObsoleteV3.cs
+++ b/src/_common/ObsoleteV3.cs
@@ -1,6 +1,8 @@
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
+// ReSharper disable all
+
namespace Skender.Stock.Indicators;
// OBSOLETE IN v3
@@ -82,7 +84,7 @@ public static IEnumerable GetTrix(
}
[Obsolete("Rename `IReusableResult` to `IReusable`", true)] // v3.0.0
-public interface IReusableResult : IReusable { }
+public interface IReusableResult : IReusable;
[ExcludeFromCodeCoverage]
[Obsolete("Rename `BasicData` to `Reusable`", true)] // v3.0.0
diff --git a/src/_common/Quotes/Quote.Aggregates.cs b/src/_common/Quotes/Quote.Aggregates.cs
index ebcf24daf..8dd87abd6 100644
--- a/src/_common/Quotes/Quote.Aggregates.cs
+++ b/src/_common/Quotes/Quote.Aggregates.cs
@@ -12,28 +12,28 @@ public static IEnumerable Aggregate(
PeriodSize newSize)
where TQuote : IQuote
{
- if (newSize != PeriodSize.Month)
- {
- // parameter conversion
- TimeSpan newTimeSpan = newSize.ToTimeSpan();
-
- // convert
- return quotes.Aggregate(newTimeSpan);
- }
- else // month
+ if (newSize == PeriodSize.Month)
{
return quotes
- .OrderBy(x => x.Timestamp)
- .GroupBy(x => new DateTime(x.Timestamp.Year, x.Timestamp.Month, 1))
- .Select(x => new Quote {
- Timestamp = x.Key,
- Open = x.First().Open,
- High = x.Max(t => t.High),
- Low = x.Min(t => t.Low),
- Close = x.Last().Close,
- Volume = x.Sum(t => t.Volume)
- });
+ .OrderBy(x => x.Timestamp)
+ .GroupBy(x => new DateTime(x.Timestamp.Year, x.Timestamp.Month, 1))
+ .Select(x => new Quote {
+ Timestamp = x.Key,
+ Open = x.First().Open,
+ High = x.Max(t => t.High),
+ Low = x.Min(t => t.Low),
+ Close = x.Last().Close,
+ Volume = x.Sum(t => t.Volume)
+ });
}
+
+ // parameter conversion
+ TimeSpan newTimeSpan = newSize.ToTimeSpan();
+
+ // convert
+ return quotes.Aggregate(newTimeSpan);
+
+ // month
}
// aggregation (quantization) using TimeSpan
diff --git a/src/_common/Quotes/Quote.Converters.cs b/src/_common/Quotes/Quote.Converters.cs
index 7e1571611..f83d8c165 100644
--- a/src/_common/Quotes/Quote.Converters.cs
+++ b/src/_common/Quotes/Quote.Converters.cs
@@ -8,52 +8,66 @@ public static partial class QuoteUtility
{
private static readonly CultureInfo NativeCulture = Thread.CurrentThread.CurrentUICulture;
- // DOUBLE QUOTES
+ /* LISTS */
- // convert to quotes in double precision
- internal static QuoteD ToQuoteD(
- this TQuote quote)
- where TQuote : IQuote => new(
- Timestamp: quote.Timestamp,
- Open: (double)quote.Open,
- High: (double)quote.High,
- Low: (double)quote.Low,
- Close: (double)quote.Close,
- Volume: (double)quote.Volume);
+ // convert TQuote type list to built-in Quote type list
+ public static IReadOnlyList ToQuoteList(
+ this IEnumerable quotes)
+ where TQuote : IQuote
+ => quotes
+ .OrderBy(x => x.Timestamp)
+ .Select(x => x.ToQuote())
+ .ToList();
+ // convert TQuote type list to QuoteD type list
internal static List ToQuoteD(
this IEnumerable quotes)
- where TQuote : IQuote => quotes
- .Select(x => new QuoteD(
- Timestamp: x.Timestamp,
- Open: (double)x.Open,
- High: (double)x.High,
- Low: (double)x.Low,
- Close: (double)x.Close,
- Volume: (double)x.Volume))
+ where TQuote : IQuote
+ => quotes
.OrderBy(x => x.Timestamp)
+ .Select(x => x.ToQuoteD())
.ToList();
- // convert quoteD type list to reusable list
- internal static List ToReusableList(
- this List qdList,
+ // convert IQuote type list to Reusable list
+ public static IReadOnlyList ToReusableList(
+ this IEnumerable quotes,
CandlePart candlePart)
- => qdList
+ where TQuote : IQuote
+ => quotes
.OrderBy(x => x.Timestamp)
.Select(x => x.ToReusable(candlePart))
.ToList();
- // convert IQuote type list to reusable list
- internal static List ToReusableList(
- this IEnumerable quotes,
+ // convert QuoteD type list to Reusable list
+ internal static List ToReusableList(
+ this List qdList,
CandlePart candlePart)
- where TQuote : IQuote
- => quotes
+ => qdList
.OrderBy(x => x.Timestamp)
.Select(x => x.ToReusable(candlePart))
.ToList();
- /* ELEMENTS */
+ /* TYPES */
+
+ // convert any IQuote type to native Quote type
+ public static Quote ToQuote(this TQuote quote)
+ where TQuote : IQuote => new(
+ Timestamp: quote.Timestamp,
+ Open: quote.Open,
+ High: quote.High,
+ Low: quote.Low,
+ Close: quote.Close,
+ Volume: quote.Volume);
+
+ // convert to quote in double precision
+ private static QuoteD ToQuoteD(this IQuote quote)
+ => new(
+ Timestamp: quote.Timestamp,
+ Open: (double)quote.Open,
+ High: (double)quote.High,
+ Low: (double)quote.Low,
+ Close: (double)quote.Close,
+ Volume: (double)quote.Volume);
// convert TQuote element to a basic chainable class
internal static Reusable ToReusable(
@@ -66,14 +80,14 @@ internal static Reusable ToReusable(
CandlePart.Low => new(q.Timestamp, (double)q.Low),
CandlePart.Close => new(q.Timestamp, (double)q.Close),
CandlePart.Volume => new(q.Timestamp, (double)q.Volume),
- CandlePart.HL2 => new(q.Timestamp, (double)(q.High + q.Low) / 2),
- CandlePart.HLC3 => new(q.Timestamp, (double)(q.High + q.Low + q.Close) / 3),
- CandlePart.OC2 => new(q.Timestamp, (double)(q.Open + q.Close) / 2),
- CandlePart.OHL3 => new(q.Timestamp, (double)(q.Open + q.High + q.Low) / 3),
- CandlePart.OHLC4 => new(q.Timestamp, (double)(q.Open + q.High + q.Low + q.Close) / 4),
+ CandlePart.Hl2 => new(q.Timestamp, (double)(q.High + q.Low) / 2),
+ CandlePart.Hlc3 => new(q.Timestamp, (double)(q.High + q.Low + q.Close) / 3),
+ CandlePart.Oc2 => new(q.Timestamp, (double)(q.Open + q.Close) / 2),
+ CandlePart.Ohl3 => new(q.Timestamp, (double)(q.Open + q.High + q.Low) / 3),
+ CandlePart.Ohlc4 => new(q.Timestamp, (double)(q.Open + q.High + q.Low + q.Close) / 4),
_ => throw new ArgumentOutOfRangeException(
- nameof(candlePart), candlePart, "Invalid candlePart provided."),
+ nameof(candlePart), candlePart, "Invalid candlePart provided.")
};
// convert quoteD element to reusable type
@@ -81,18 +95,19 @@ internal static Reusable ToReusable(
this QuoteD q,
CandlePart candlePart)
=> candlePart switch {
+
CandlePart.Open => new(q.Timestamp, q.Open),
CandlePart.High => new(q.Timestamp, q.High),
CandlePart.Low => new(q.Timestamp, q.Low),
CandlePart.Close => new(q.Timestamp, q.Close),
CandlePart.Volume => new(q.Timestamp, q.Volume),
- CandlePart.HL2 => new(q.Timestamp, (q.High + q.Low) / 2),
- CandlePart.HLC3 => new(q.Timestamp, (q.High + q.Low + q.Close) / 3),
- CandlePart.OC2 => new(q.Timestamp, (q.Open + q.Close) / 2),
- CandlePart.OHL3 => new(q.Timestamp, (q.Open + q.High + q.Low) / 3),
- CandlePart.OHLC4 => new(q.Timestamp, (q.Open + q.High + q.Low + q.Close) / 4),
+ CandlePart.Hl2 => new(q.Timestamp, (q.High + q.Low) / 2),
+ CandlePart.Hlc3 => new(q.Timestamp, (q.High + q.Low + q.Close) / 3),
+ CandlePart.Oc2 => new(q.Timestamp, (q.Open + q.Close) / 2),
+ CandlePart.Ohl3 => new(q.Timestamp, (q.Open + q.High + q.Low) / 3),
+ CandlePart.Ohlc4 => new(q.Timestamp, (q.Open + q.High + q.Low + q.Close) / 4),
_ => throw new ArgumentOutOfRangeException(
- nameof(candlePart), candlePart, "Invalid candlePart provided."),
+ nameof(candlePart), candlePart, "Invalid candlePart provided.")
};
}
diff --git a/src/_common/Quotes/Quote.Models.cs b/src/_common/Quotes/Quote.Models.cs
index b26b8f1b5..5c4b8aa1f 100644
--- a/src/_common/Quotes/Quote.Models.cs
+++ b/src/_common/Quotes/Quote.Models.cs
@@ -11,7 +11,9 @@ namespace Skender.Stock.Indicators;
///
///
/// (A) For streaming compatibility, define it as a
-/// value-based type.
+/// value-based type. Add
+/// the keyword modifier for
+/// slightly better memory performance.
///
///
/// (B) For chaining compatibility (
diff --git a/src/_common/Quotes/Quote.Validation.cs b/src/_common/Quotes/Quote.Validation.cs
index 30ab58d02..e8e24fdf2 100644
--- a/src/_common/Quotes/Quote.Validation.cs
+++ b/src/_common/Quotes/Quote.Validation.cs
@@ -30,4 +30,9 @@ public static IEnumerable Validate(
return quotesList;
}
+
+ // public static TQuote Validate(TQuote quote) where TQuote : IQuote
+ // {
+ //
+ // }
}
diff --git a/src/_common/Results/Result.Utilities.cs b/src/_common/Results/Result.Utilities.cs
index 81e6df677..c42279943 100644
--- a/src/_common/Results/Result.Utilities.cs
+++ b/src/_common/Results/Result.Utilities.cs
@@ -1,10 +1,8 @@
-using System.Collections.ObjectModel;
-
namespace Skender.Stock.Indicators;
// RESULTS UTILITIES
-public static partial class ResultUtility
+public static class ResultUtility
{
// CONDENSE (REMOVE null and NaN results)
///
diff --git a/src/_common/Use (quote converter)/Use.Stream.cs b/src/_common/Use (quote converter)/Use.Stream.cs
index 91cc2187c..e9884abed 100644
--- a/src/_common/Use (quote converter)/Use.Stream.cs
+++ b/src/_common/Use (quote converter)/Use.Stream.cs
@@ -6,8 +6,6 @@ public class Use
: AbstractQuoteInChainOut, IUse
where TQuote : struct, IQuote
{
- #region CONSTRUCTORS
-
public Use(
IQuoteProvider provider,
CandlePart candlePart) : base(provider)
@@ -19,12 +17,8 @@ public Use(
? throw new ArgumentNullException(nameof(provider))
: provider.Subscribe(this);
}
- #endregion
- # region PROPERTIES
-
- public CandlePart CandlePartSelection { get; private set; }
- #endregion
+ public CandlePart CandlePartSelection { get; }
# region METHODS
diff --git a/src/a-d/Adl/Adl.Api.cs b/src/a-d/Adl/Adl.Api.cs
index 8eaea2d37..879522287 100644
--- a/src/a-d/Adl/Adl.Api.cs
+++ b/src/a-d/Adl/Adl.Api.cs
@@ -5,8 +5,17 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
// SERIES, from TQuote
- ///
- ///
+ ///
+ ///Accumulation / Distribution Line(ADL) is a rolling accumulation of Chaikin Money Flow Volume.
+ ///
+ ///See
+ /// documentation
+ ///for more information.
+ ///
+ ///
+ /// Configurable Quote type. See Guide for more information.
+ ///Historical price quotes.
+ ///Time series of ADL values.
public static IEnumerable GetAdl(
this IEnumerable quotes)
where TQuote : IQuote
diff --git a/src/a-d/Adl/Adl.Common.cs b/src/a-d/Adl/Adl.Common.cs
index a3d7c0521..85956b450 100644
--- a/src/a-d/Adl/Adl.Common.cs
+++ b/src/a-d/Adl/Adl.Common.cs
@@ -5,7 +5,7 @@ namespace Skender.Stock.Indicators;
/// See the
/// Stock Indicators for .NET online guide for more information.
-public static partial class Adl
+public static class Adl
{
// increment calculation
/// Get the next incremental Accumulation/Distribution Line(ADL) value.
@@ -30,11 +30,11 @@ public static AdlResult Increment(
double close,
double volume)
{
- double mfm = (high == low) ? 0 : (close - low - (high - close)) / (high - low);
+ double mfm = high - low == 0 ? 0 : (close - low - (high - close)) / (high - low);
double mfv = mfm * volume;
double adl = mfv + prevAdl;
- return new AdlResult(
+ return new(
Timestamp: timestamp,
Adl: adl,
MoneyFlowMultiplier: mfm,
diff --git a/src/a-d/Adl/Adl.Series.cs b/src/a-d/Adl/Adl.Series.cs
index 7a14579d2..12d9c9f8d 100644
--- a/src/a-d/Adl/Adl.Series.cs
+++ b/src/a-d/Adl/Adl.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcAdl(
+ private static List CalcAdl(
this List qdList)
{
// initialize
diff --git a/src/a-d/Adl/Adl.Stream.cs b/src/a-d/Adl/Adl.Stream.cs
index 07652091f..bb815886c 100644
--- a/src/a-d/Adl/Adl.Stream.cs
+++ b/src/a-d/Adl/Adl.Stream.cs
@@ -2,7 +2,7 @@ namespace Skender.Stock.Indicators;
// ACCUMULATION/DISTRIBUTION LINE (STREAM)
-public partial class Adl : AbstractQuoteInChainOut, IAdl
+public class Adl : AbstractQuoteInChainOut, IAdl
where TQuote : struct, IQuote
{
#region CONSTRUCTORS
diff --git a/src/a-d/Adl/info.xml b/src/a-d/Adl/info.xml
deleted file mode 100644
index cb124315a..000000000
--- a/src/a-d/Adl/info.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
-
-
-
- Accumulation/Distribution Line (ADL) is a rolling accumulation of Chaikin Money Flow Volume.
-
- See
- documentation
- for more information.
-
-
- Configurable Quote type. See Guide for more information.
- Historical price quotes.
- Time series of ADL values.
-
-
diff --git a/src/a-d/Adx/Adx.Series.cs b/src/a-d/Adx/Adx.Series.cs
index 02fe473f8..fefab13e7 100644
--- a/src/a-d/Adx/Adx.Series.cs
+++ b/src/a-d/Adx/Adx.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcAdx(
+ private static List CalcAdx(
this List qdList,
int lookbackPeriods)
{
@@ -40,7 +40,7 @@ internal static List CalcAdx(
prevLow = q.Low;
prevClose = q.Close;
- results.Add(new AdxResult(Timestamp: q.Timestamp));
+ results.Add(new(Timestamp: q.Timestamp));
continue;
}
@@ -69,7 +69,7 @@ internal static List CalcAdx(
// skip DM initialization period
if (i < lookbackPeriods)
{
- results.Add(new AdxResult(Timestamp: q.Timestamp));
+ results.Add(new(Timestamp: q.Timestamp));
continue;
}
@@ -87,9 +87,9 @@ internal static List CalcAdx(
}
else
{
- trs = prevTrs - (prevTrs / lookbackPeriods) + tr;
- pdm = prevPdm - (prevPdm / lookbackPeriods) + pdm1;
- mdm = prevMdm - (prevMdm / lookbackPeriods) + mdm1;
+ trs = prevTrs - prevTrs / lookbackPeriods + tr;
+ pdm = prevPdm - prevPdm / lookbackPeriods + pdm1;
+ mdm = prevMdm - prevMdm / lookbackPeriods + mdm1;
}
prevTrs = trs;
@@ -98,7 +98,7 @@ internal static List CalcAdx(
if (trs is 0)
{
- results.Add(new AdxResult(Timestamp: q.Timestamp));
+ results.Add(new(Timestamp: q.Timestamp));
continue;
}
@@ -107,18 +107,18 @@ internal static List CalcAdx(
double mdi = 100 * mdm / trs;
// calculate ADX
- double dx = (pdi == mdi)
+ double dx = pdi - mdi == 0
? 0
- : (pdi + mdi != 0)
+ : pdi + mdi != 0
? 100 * Math.Abs(pdi - mdi) / (pdi + mdi)
: double.NaN;
double adx = double.NaN;
double adxr = double.NaN;
- if (i > (2 * lookbackPeriods) - 1)
+ if (i > 2 * lookbackPeriods - 1)
{
- adx = ((prevAdx * (lookbackPeriods - 1)) + dx) / lookbackPeriods;
+ adx = (prevAdx * (lookbackPeriods - 1) + dx) / lookbackPeriods;
double priorAdx = results[i - lookbackPeriods + 1].Adx.Null2NaN();
@@ -127,7 +127,7 @@ internal static List CalcAdx(
}
// initial ADX
- else if (i == (2 * lookbackPeriods) - 1)
+ else if (i == 2 * lookbackPeriods - 1)
{
sumDx += dx;
adx = sumDx / lookbackPeriods;
diff --git a/src/a-d/Adx/Adx.Utilities.cs b/src/a-d/Adx/Adx.Utilities.cs
index 9f815a1ac..f6029d37e 100644
--- a/src/a-d/Adx/Adx.Utilities.cs
+++ b/src/a-d/Adx/Adx.Utilities.cs
@@ -12,6 +12,6 @@ public static IEnumerable RemoveWarmupPeriods(
.ToList()
.FindIndex(x => x.Pdi != null);
- return results.Remove((2 * n) + 100);
+ return results.Remove(2 * n + 100);
}
}
diff --git a/src/a-d/Alligator/Alligator.Series.cs b/src/a-d/Alligator/Alligator.Series.cs
index fcc278b08..0c4f6033f 100644
--- a/src/a-d/Alligator/Alligator.Series.cs
+++ b/src/a-d/Alligator/Alligator.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcAlligator(
+ private static List CalcAlligator(
this List source,
int jawPeriods,
int jawOffset,
@@ -29,7 +29,7 @@ List feed
? source
.Cast()
- .Use(CandlePart.HL2)
+ .Use(CandlePart.Hl2)
.Cast()
.ToSortedList()
@@ -68,7 +68,7 @@ List feed
// remaining values: SMMA
else
{
- jaw = ((prevJaw * (jawPeriods - 1)) + feed[i - jawOffset].Value) / jawPeriods;
+ jaw = (prevJaw * (jawPeriods - 1) + feed[i - jawOffset].Value) / jawPeriods;
}
}
@@ -92,7 +92,7 @@ List feed
// remaining values: SMMA
else
{
- teeth = ((prevTooth * (teethPeriods - 1)) + feed[i - teethOffset].Value) / teethPeriods;
+ teeth = (prevTooth * (teethPeriods - 1) + feed[i - teethOffset].Value) / teethPeriods;
}
}
@@ -116,7 +116,7 @@ List feed
// remaining values: SMMA
else
{
- lips = ((prevLips * (lipsPeriods - 1)) + feed[i - lipsOffset].Value) / lipsPeriods;
+ lips = (prevLips * (lipsPeriods - 1) + feed[i - lipsOffset].Value) / lipsPeriods;
}
}
diff --git a/src/a-d/Alligator/Alligator.Stream.cs b/src/a-d/Alligator/Alligator.Stream.cs
index 8bf339e7f..2776bf44a 100644
--- a/src/a-d/Alligator/Alligator.Stream.cs
+++ b/src/a-d/Alligator/Alligator.Stream.cs
@@ -40,12 +40,12 @@ public Alligator(
# region PROPERTIES
- public int JawPeriods { get; private set; }
- public int JawOffset { get; private set; }
- public int TeethPeriods { get; private set; }
- public int TeethOffset { get; private set; }
- public int LipsPeriods { get; private set; }
- public int LipsOffset { get; private set; }
+ public int JawPeriods { get; }
+ public int JawOffset { get; }
+ public int TeethPeriods { get; }
+ public int TeethOffset { get; }
+ public int LipsPeriods { get; }
+ public int LipsOffset { get; }
#endregion
# region METHODS
@@ -97,7 +97,7 @@ protected override void OnNextArrival(Act act, TIn inbound)
double sum = 0;
for (int p = i - JawPeriods - JawOffset + 1; p <= i - JawOffset; p++)
{
- sum += ToValue(ProviderCache[p]);
+ sum += _toValue(ProviderCache[p]);
}
jaw = sum / JawPeriods;
@@ -106,8 +106,8 @@ protected override void OnNextArrival(Act act, TIn inbound)
// remaining values: SMMA
else
{
- double newVal = ToValue(ProviderCache[i - JawOffset]);
- jaw = ((prevJaw * (JawPeriods - 1)) + newVal) / JawPeriods;
+ double newVal = _toValue(ProviderCache[i - JawOffset]);
+ jaw = (prevJaw * (JawPeriods - 1) + newVal) / JawPeriods;
}
}
@@ -122,7 +122,7 @@ protected override void OnNextArrival(Act act, TIn inbound)
double sum = 0;
for (int p = i - TeethPeriods - TeethOffset + 1; p <= i - TeethOffset; p++)
{
- sum += ToValue(ProviderCache[p]);
+ sum += _toValue(ProviderCache[p]);
}
teeth = sum / TeethPeriods;
@@ -131,8 +131,8 @@ protected override void OnNextArrival(Act act, TIn inbound)
// remaining values: SMMA
else
{
- double newVal = ToValue(ProviderCache[i - TeethOffset]);
- teeth = ((prevTooth * (TeethPeriods - 1)) + newVal) / TeethPeriods;
+ double newVal = _toValue(ProviderCache[i - TeethOffset]);
+ teeth = (prevTooth * (TeethPeriods - 1) + newVal) / TeethPeriods;
}
}
@@ -147,7 +147,7 @@ protected override void OnNextArrival(Act act, TIn inbound)
double sum = 0;
for (int p = i - LipsPeriods - LipsOffset + 1; p <= i - LipsOffset; p++)
{
- sum += ToValue(ProviderCache[p]);
+ sum += _toValue(ProviderCache[p]);
}
lips = sum / LipsPeriods;
@@ -156,8 +156,8 @@ protected override void OnNextArrival(Act act, TIn inbound)
// remaining values: SMMA
else
{
- double newVal = ToValue(ProviderCache[i - LipsOffset]);
- lips = ((prevLips * (LipsPeriods - 1)) + newVal) / LipsPeriods;
+ double newVal = _toValue(ProviderCache[i - LipsOffset]);
+ lips = (prevLips * (LipsPeriods - 1) + newVal) / LipsPeriods;
}
}
}
@@ -187,8 +187,8 @@ protected override void OnNextArrival(Act act, TIn inbound)
#endregion
// convert provider IQuotes to HL2, if needed
- private readonly Func ToValue
- = (input) => input is IQuote quote
- ? quote.ToReusable(CandlePart.HL2).Value
+ private readonly Func _toValue
+ = input => input is IQuote quote
+ ? quote.ToReusable(CandlePart.Hl2).Value
: input.Value;
}
diff --git a/src/a-d/Alma/Alma.Series.cs b/src/a-d/Alma/Alma.Series.cs
index dde7ebd54..59e6f1c75 100644
--- a/src/a-d/Alma/Alma.Series.cs
+++ b/src/a-d/Alma/Alma.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcAlma(
+ private static List CalcAlma(
this List source,
int lookbackPeriods,
double offset,
diff --git a/src/a-d/Aroon/Aroon.Series.cs b/src/a-d/Aroon/Aroon.Series.cs
index 536641949..572b55d09 100644
--- a/src/a-d/Aroon/Aroon.Series.cs
+++ b/src/a-d/Aroon/Aroon.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcAroon(
+ private static List CalcAroon(
this List qdList,
int lookbackPeriods)
{
diff --git a/src/a-d/Atr/Atr.Series.cs b/src/a-d/Atr/Atr.Series.cs
index 9c86116a9..4268e8a06 100644
--- a/src/a-d/Atr/Atr.Series.cs
+++ b/src/a-d/Atr/Atr.Series.cs
@@ -5,7 +5,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
// calculate series
- internal static List CalcAtr(
+ private static List CalcAtr(
this List qdList,
int lookbackPeriods)
{
@@ -43,8 +43,8 @@ internal static List CalcAtr(
if (i > lookbackPeriods)
{
// calculate ATR
- atr = ((prevAtr * (lookbackPeriods - 1)) + tr) / lookbackPeriods;
- atrp = (q.Close == 0) ? null : atr / q.Close * 100;
+ atr = (prevAtr * (lookbackPeriods - 1) + tr) / lookbackPeriods;
+ atrp = q.Close == 0 ? null : atr / q.Close * 100;
prevAtr = atr;
}
@@ -54,7 +54,7 @@ internal static List CalcAtr(
// initialize ATR
sumTr += tr;
atr = sumTr / lookbackPeriods;
- atrp = (q.Close == 0) ? null : atr / q.Close * 100;
+ atrp = q.Close == 0 ? null : atr / q.Close * 100;
prevAtr = atr;
}
diff --git a/src/a-d/AtrStop/AtrStop.Series.cs b/src/a-d/AtrStop/AtrStop.Series.cs
index 63a768c5b..d0fd90fb9 100644
--- a/src/a-d/AtrStop/AtrStop.Series.cs
+++ b/src/a-d/AtrStop/AtrStop.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcAtrStop(
+ private static List CalcAtrStop(
this List qdList,
int lookbackPeriods,
double multiplier,
@@ -42,15 +42,15 @@ internal static List CalcAtrStop(
// potential bands for CLOSE
if (endType == EndType.Close)
{
- upperEval = q.Close + (multiplier * atr);
- lowerEval = q.Close - (multiplier * atr);
+ upperEval = q.Close + multiplier * atr;
+ lowerEval = q.Close - multiplier * atr;
}
// potential bands for HIGH/LOW
else
{
- upperEval = q.High + (multiplier * atr);
- lowerEval = q.Low - (multiplier * atr);
+ upperEval = q.High + multiplier * atr;
+ lowerEval = q.Low - multiplier * atr;
}
// initial values
diff --git a/src/a-d/Awesome/Awesome.Series.cs b/src/a-d/Awesome/Awesome.Series.cs
index eab0edc4d..3376e73b2 100644
--- a/src/a-d/Awesome/Awesome.Series.cs
+++ b/src/a-d/Awesome/Awesome.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcAwesome(
+ private static List CalcAwesome(
this List source,
int fastPeriods,
int slowPeriods)
@@ -19,7 +19,7 @@ List feed
? source
.Cast()
- .Use(CandlePart.HL2)
+ .Use(CandlePart.Hl2)
.Cast()
.ToSortedList()
@@ -56,8 +56,8 @@ List feed
}
}
- oscillator = ((sumFast / fastPeriods) - (sumSlow / slowPeriods)).NaN2Null();
- normalized = (pr[i] != 0) ? 100 * oscillator / pr[i] : null;
+ oscillator = (sumFast / fastPeriods - sumSlow / slowPeriods).NaN2Null();
+ normalized = pr[i] != 0 ? 100 * oscillator / pr[i] : null;
}
AwesomeResult r = new(
diff --git a/src/a-d/Beta/Beta.Series.cs b/src/a-d/Beta/Beta.Series.cs
index f9b29a8f7..126cfc0c3 100644
--- a/src/a-d/Beta/Beta.Series.cs
+++ b/src/a-d/Beta/Beta.Series.cs
@@ -5,7 +5,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
// NOTE: sequence swapped from API
- internal static List CalcBeta(
+ private static List CalcBeta(
List sourceEval,
List sourceMrkt,
int lookbackPeriods,
@@ -40,8 +40,8 @@ internal static List CalcBeta(
"Timestamp sequence does not match. Beta requires matching dates in provided quotes.");
}
- evalReturns[i] = prevE != 0 ? (eval.Value / prevE) - 1d : 0;
- mrktReturns[i] = prevM != 0 ? (mrkt.Value / prevM) - 1d : 0;
+ evalReturns[i] = prevE != 0 ? eval.Value / prevE - 1d : 0;
+ mrktReturns[i] = prevM != 0 ? mrkt.Value / prevM - 1d : 0;
prevE = eval.Value;
prevM = mrkt.Value;
@@ -56,7 +56,7 @@ internal static List CalcBeta(
if (i < lookbackPeriods)
{
results.Add(
- new BetaResult(
+ new(
Timestamp: eval.Timestamp,
ReturnsEval: evalReturns[i],
ReturnsMrkt: mrktReturns[i]));
@@ -92,12 +92,12 @@ internal static List CalcBeta(
// ratio and convexity
if (type == BetaType.All && betaUp != null && betaDown != null)
{
- ratio = (betaDown != 0) ? betaUp / betaDown : null;
+ ratio = betaDown != 0 ? betaUp / betaDown : null;
convexity = (betaUp - betaDown) * (betaUp - betaDown);
}
results.Add(
- new BetaResult(
+ new(
Timestamp: eval.Timestamp,
ReturnsEval: evalReturns[i],
ReturnsMrkt: mrktReturns[i],
@@ -131,28 +131,32 @@ internal static List CalcBeta(
double a = mrktReturns[p];
double b = evalReturns[p];
- if (type is BetaType.Standard
- || (type is BetaType.Down && a < 0)
- || (type is BetaType.Up && a > 0))
+ if (type is not BetaType.Standard
+ && (type is not BetaType.Down || !(a < 0))
+ && (type is not BetaType.Up || !(a > 0)))
{
- dataA.Add(a);
- dataB.Add(b);
+ continue;
}
+
+ dataA.Add(a);
+ dataB.Add(b);
}
- if (dataA.Count > 0)
+ if (dataA.Count <= 0)
{
- // calculate correlation, covariance, and variance
- CorrResult c = PeriodCorrelation(
- default,
- [.. dataA],
- [.. dataB]);
-
- // calculate beta
- if (c.Covariance != null && c.VarianceA != null && c.VarianceA != 0)
- {
- beta = (c.Covariance / c.VarianceA).NaN2Null();
- }
+ return beta;
+ }
+
+ // calculate correlation, covariance, and variance
+ CorrResult c = PeriodCorrelation(
+ default,
+ [.. dataA],
+ [.. dataB]);
+
+ // calculate beta
+ if (c is { Covariance: not null, VarianceA: not null } && c.VarianceA != 0)
+ {
+ beta = (c.Covariance / c.VarianceA).NaN2Null();
}
return beta;
diff --git a/src/a-d/BollingerBands/BollingerBands.Series.cs b/src/a-d/BollingerBands/BollingerBands.Series.cs
index 57add4513..96361c2fc 100644
--- a/src/a-d/BollingerBands/BollingerBands.Series.cs
+++ b/src/a-d/BollingerBands/BollingerBands.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcBollingerBands(
+ private static List CalcBollingerBands(
this List source,
int lookbackPeriods,
double standardDeviations)
@@ -38,10 +38,10 @@ internal static List CalcBollingerBands(
double? sma = (sum / lookbackPeriods).NaN2Null();
double? stdDev = window.StdDev().NaN2Null();
- double? upperBand = sma + (standardDeviations * stdDev);
- double? lowerBand = sma - (standardDeviations * stdDev);
+ double? upperBand = sma + standardDeviations * stdDev;
+ double? lowerBand = sma - standardDeviations * stdDev;
- results.Add(new BollingerBandsResult(
+ results.Add(new(
Timestamp: s.Timestamp,
@@ -49,11 +49,11 @@ internal static List CalcBollingerBands(
UpperBand: upperBand,
LowerBand: lowerBand,
- PercentB: (upperBand == lowerBand) ? null
+ PercentB: upperBand - lowerBand == 0 ? null
: (s.Value - lowerBand) / (upperBand - lowerBand),
- ZScore: (stdDev == 0) ? null : (s.Value - sma) / stdDev,
- Width: (sma == 0) ? null : (upperBand - lowerBand) / sma
+ ZScore: stdDev == 0 ? null : (s.Value - sma) / stdDev,
+ Width: sma == 0 ? null : (upperBand - lowerBand) / sma
));
}
diff --git a/src/a-d/Bop/Bop.Series.cs b/src/a-d/Bop/Bop.Series.cs
index 7632ea263..892df24d2 100644
--- a/src/a-d/Bop/Bop.Series.cs
+++ b/src/a-d/Bop/Bop.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcBop(
+ private static List CalcBop(
this List qdList,
int smoothPeriods)
{
@@ -16,8 +16,8 @@ internal static List CalcBop(
List results = new(length);
double[] raw = qdList
- .Select(x => (x.High != x.Low) ?
- ((x.Close - x.Open) / (x.High - x.Low)) : double.NaN)
+ .Select(x => x.High - x.Low != 0 ?
+ (x.Close - x.Open) / (x.High - x.Low) : double.NaN)
.ToArray();
// roll through quotes
@@ -36,7 +36,7 @@ internal static List CalcBop(
bop = (sum / smoothPeriods).NaN2Null();
}
- results.Add(new BopResult(
+ results.Add(new(
Timestamp: qdList[i].Timestamp,
Bop: bop));
}
diff --git a/src/a-d/Cci/Cci.Series.cs b/src/a-d/Cci/Cci.Series.cs
index 9ace7e887..cec7550eb 100644
--- a/src/a-d/Cci/Cci.Series.cs
+++ b/src/a-d/Cci/Cci.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcCci(
+ private static List CalcCci(
this List qdList,
int lookbackPeriods)
{
@@ -44,11 +44,11 @@ internal static List CalcCci(
avgDv /= lookbackPeriods;
- cci = (avgDv == 0) ? null
+ cci = avgDv == 0 ? null
: ((tp[i] - avgTp) / (0.015 * avgDv)).NaN2Null();
}
- results.Add(new CciResult(
+ results.Add(new(
Timestamp: q.Timestamp,
Cci: cci));
}
diff --git a/src/a-d/ChaikinOsc/ChaikinOsc.Series.cs b/src/a-d/ChaikinOsc/ChaikinOsc.Series.cs
index 4c93436a1..daa4eed82 100644
--- a/src/a-d/ChaikinOsc/ChaikinOsc.Series.cs
+++ b/src/a-d/ChaikinOsc/ChaikinOsc.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcChaikinOsc(
+ private static List CalcChaikinOsc(
this List qdList,
int fastPeriods,
int slowPeriods)
@@ -30,7 +30,7 @@ internal static List CalcChaikinOsc(
EmaResult f = adlEmaFast[i];
EmaResult s = adlEmaSlow[i];
- results.Add(new ChaikinOscResult(
+ results.Add(new(
Timestamp: a.Timestamp,
MoneyFlowMultiplier: a.MoneyFlowMultiplier,
MoneyFlowVolume: a.MoneyFlowVolume,
diff --git a/src/a-d/Chandelier/Chandelier.Series.cs b/src/a-d/Chandelier/Chandelier.Series.cs
index 338df8cf7..28e434e7c 100644
--- a/src/a-d/Chandelier/Chandelier.Series.cs
+++ b/src/a-d/Chandelier/Chandelier.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcChandelier(
+ private static List CalcChandelier(
this List qdList,
int lookbackPeriods,
double multiplier,
@@ -46,7 +46,7 @@ internal static List CalcChandelier(
}
}
- exit = maxHigh - (atr * multiplier);
+ exit = maxHigh - atr * multiplier;
break;
case ChandelierType.Short:
@@ -61,7 +61,7 @@ internal static List CalcChandelier(
}
}
- exit = minLow + (atr * multiplier);
+ exit = minLow + atr * multiplier;
break;
default:
@@ -69,7 +69,7 @@ internal static List CalcChandelier(
}
}
- results.Add(new ChandelierResult(
+ results.Add(new(
Timestamp: q.Timestamp,
ChandelierExit: exit));
}
diff --git a/src/a-d/Chop/Chop.Series.cs b/src/a-d/Chop/Chop.Series.cs
index e1ccba813..c80a338fa 100644
--- a/src/a-d/Chop/Chop.Series.cs
+++ b/src/a-d/Chop/Chop.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcChop(
+ private static List CalcChop(
this List qdList,
int lookbackPeriods)
{
@@ -12,11 +12,6 @@ internal static List CalcChop(
Chop.Validate(lookbackPeriods);
// initialize
- double sum;
- double high;
- double low;
- double range;
-
int length = qdList.Count;
List results = new(length);
double[] trueHigh = new double[length];
@@ -39,9 +34,9 @@ internal static List CalcChop(
if (i >= lookbackPeriods)
{
// reset measurements
- sum = trueRange[i];
- high = trueHigh[i];
- low = trueLow[i];
+ double sum = trueRange[i];
+ double high = trueHigh[i];
+ double low = trueLow[i];
// iterate over lookback window
for (int j = 1; j < lookbackPeriods; j++)
@@ -51,7 +46,7 @@ internal static List CalcChop(
low = Math.Min(low, trueLow[i - j]);
}
- range = high - low;
+ double range = high - low;
// calculate CHOP
if (range != 0)
@@ -61,7 +56,7 @@ internal static List CalcChop(
}
}
- results.Add(new ChopResult(
+ results.Add(new(
Timestamp: qdList[i].Timestamp,
Chop: chop));
}
diff --git a/src/a-d/Cmf/Cmf.Series.cs b/src/a-d/Cmf/Cmf.Series.cs
index c1c14a5e0..d8c546fc1 100644
--- a/src/a-d/Cmf/Cmf.Series.cs
+++ b/src/a-d/Cmf/Cmf.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcCmf(
+ private static List CalcCmf(
this List qdList,
int lookbackPeriods)
{
@@ -49,7 +49,7 @@ List source
}
}
- results.Add(new CmfResult(
+ results.Add(new(
Timestamp: adl.Timestamp,
MoneyFlowMultiplier: adl.MoneyFlowMultiplier,
MoneyFlowVolume: adl.MoneyFlowVolume,
diff --git a/src/a-d/Cmo/Cmo.Series.cs b/src/a-d/Cmo/Cmo.Series.cs
index 1111993a0..1a467286c 100644
--- a/src/a-d/Cmo/Cmo.Series.cs
+++ b/src/a-d/Cmo/Cmo.Series.cs
@@ -4,7 +4,7 @@ namespace Skender.Stock.Indicators;
public static partial class Indicator
{
- internal static List CalcCmo(
+ private static List CalcCmo(
this List