clean code fixes

This commit is contained in:
Miha Kralj
2024-10-06 17:16:47 -07:00
parent bcac34bf09
commit b7b5a4a1bf
52 changed files with 787 additions and 643 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ public class Entropy : AbstractBase
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when the period is less than 2.
/// </exception>
public Entropy(int period) : base()
public Entropy(int period)
{
if (period < 2)
{
+1 -1
View File
@@ -16,7 +16,7 @@ public class Kurtosis : AbstractBase
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when the period is less than 4.
/// </exception>
public Kurtosis(int period) : base()
public Kurtosis(int period)
{
if (period < 4)
{
+2 -2
View File
@@ -20,7 +20,7 @@ public class Max : AbstractBase
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when the period is less than 1 or decay is negative.
/// </exception>
public Max(int period, double decay = 0) : base()
public Max(int period, double decay = 0)
{
if (period < 1)
{
@@ -105,7 +105,7 @@ public class Max : AbstractBase
}
double decayRate = 1 - Math.Exp(-_halfLife * _timeSinceNewMax / Period);
_currentMax = _currentMax - decayRate * (_currentMax - _buffer.Average());
_currentMax -= decayRate * (_currentMax - _buffer.Average());
_currentMax = Math.Min(_currentMax, _buffer.Max());
IsHot = true;
+2 -11
View File
@@ -16,7 +16,7 @@ public class Median : AbstractBase
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when the period is less than 1.
/// </exception>
public Median(int period) : base()
public Median(int period)
{
if (period < 1)
{
@@ -76,16 +76,7 @@ public class Median : AbstractBase
Array.Sort(sortedValues);
int middleIndex = sortedValues.Length / 2;
if (sortedValues.Length % 2 == 0)
{
// Even number of values: average of two middle values
median = (sortedValues[middleIndex - 1] + sortedValues[middleIndex]) / 2.0;
}
else
{
// Odd number of values: middle value
median = sortedValues[middleIndex];
}
median = (sortedValues.Length % 2 == 0) ? (sortedValues[middleIndex - 1] + sortedValues[middleIndex]) / 2.0 : sortedValues[middleIndex];
}
else
{
+24 -12
View File
@@ -10,7 +10,8 @@ namespace QuanTAlib;
/// efficiently. It also implements a decay mechanism to adjust the minimum value over
/// time, allowing for a more responsive indicator in changing market conditions.
/// </remarks>
public class Min : AbstractBase {
public class Min : AbstractBase
{
private readonly int Period;
private readonly CircularBuffer _buffer;
private readonly double _halfLife;
@@ -25,11 +26,14 @@ public class Min : AbstractBase {
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1 or decay is negative.
/// </exception>
public Min(int period, double decay = 0) : base() {
if (period < 1) {
public Min(int period, double decay = 0)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
if (decay < 0) {
if (decay < 0)
{
throw new ArgumentOutOfRangeException(nameof(decay), "Half-life must be non-negative.");
}
Period = period;
@@ -46,7 +50,8 @@ public class Min : AbstractBase {
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the minimum value.</param>
/// <param name="decay">The decay factor to apply to older values (default is 0).</param>
public Min(object source, int period, double decay = 0) : this(period, decay) {
public Min(object source, int period, double decay = 0) : this(period, decay)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
@@ -54,7 +59,8 @@ public class Min : AbstractBase {
/// <summary>
/// Initializes the Min instance by setting initial values.
/// </summary>
public override void Init() {
public override void Init()
{
base.Init();
_currentMin = double.MaxValue;
_timeSinceNewMin = 0;
@@ -64,14 +70,18 @@ public class Min : AbstractBase {
/// Manages the state of the Min instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew) {
if (isNew) {
protected override void ManageState(bool isNew)
{
if (isNew)
{
_p_currentMin = _currentMin;
_lastValidValue = Input.Value;
_index++;
_timeSinceNewMin++;
_p_timeSinceNewMin = _timeSinceNewMin;
} else {
}
else
{
_currentMin = _p_currentMin;
_timeSinceNewMin = _p_timeSinceNewMin;
}
@@ -87,17 +97,19 @@ public class Min : AbstractBase {
/// The decay rate is calculated using an exponential function based on the time since
/// the last new minimum and the specified half-life.
/// </remarks>
protected override double Calculation() {
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
if (Input.Value <= _currentMin) {
if (Input.Value <= _currentMin)
{
_currentMin = Input.Value;
_timeSinceNewMin = 0;
}
double decayRate = 1 - Math.Exp(-_halfLife * _timeSinceNewMin / Period);
_currentMin = _currentMin + decayRate * (_buffer.Average() - _currentMin);
_currentMin += decayRate * (_buffer.Average() - _currentMin);
_currentMin = Math.Max(_currentMin, _buffer.Min());
IsHot = true;
+19 -9
View File
@@ -9,7 +9,8 @@ namespace QuanTAlib;
/// efficiently. Before the specified period is reached, it returns the average of
/// the available values as an approximation.
/// </remarks>
public class Mode : AbstractBase {
public class Mode : AbstractBase
{
private readonly int Period;
private readonly CircularBuffer _buffer;
@@ -20,8 +21,10 @@ public class Mode : AbstractBase {
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 1.
/// </exception>
public Mode(int period) : base() {
if (period < 1) {
public Mode(int period)
{
if (period < 1)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 1.");
}
Period = period;
@@ -36,7 +39,8 @@ public class Mode : AbstractBase {
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the mode.</param>
public Mode(object source, int period) : this(period) {
public Mode(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
@@ -45,8 +49,10 @@ public class Mode : AbstractBase {
/// Manages the state of the Mode instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew) {
if (isNew) {
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
@@ -64,12 +70,14 @@ public class Mode : AbstractBase {
/// the available values as an approximation of the mode. Once the period is
/// reached, it calculates the true mode by grouping and counting the values.
/// </remarks>
protected override double Calculation() {
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
double mode;
if (_index >= Period) {
if (_index >= Period)
{
var values = _buffer.GetSpan().ToArray();
var groupedValues = values.GroupBy(v => v)
.OrderByDescending(g => g.Count())
@@ -82,7 +90,9 @@ public class Mode : AbstractBase {
.ToList();
mode = modes.Average(); // If there are multiple modes, we return their average
} else {
}
else
{
mode = _buffer.Average(); // Use average until we have enough data points
}
+28 -13
View File
@@ -10,7 +10,8 @@ namespace QuanTAlib;
/// between two data points. Before the specified period is reached, it returns the
/// average of the available values as an approximation.
/// </remarks>
public class Percentile : AbstractBase {
public class Percentile : AbstractBase
{
private readonly int Period;
private readonly double Percent;
private readonly CircularBuffer _buffer;
@@ -23,11 +24,14 @@ public class Percentile : AbstractBase {
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 2 or percent is not between 0 and 100.
/// </exception>
public Percentile(int period, double percent) : base() {
if (period < 2) {
public Percentile(int period, double percent)
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2 for percentile calculation.");
}
if (percent < 0 || percent > 100) {
if (percent < 0 || percent > 100)
{
throw new ArgumentOutOfRangeException(nameof(percent), "Percent must be between 0 and 100.");
}
Period = period;
@@ -44,7 +48,8 @@ public class Percentile : AbstractBase {
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the percentile.</param>
/// <param name="percent">The percentile to calculate (between 0 and 100).</param>
public Percentile(object source, int period, double percent) : this(period, percent) {
public Percentile(object source, int period, double percent) : this(period, percent)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
@@ -52,7 +57,8 @@ public class Percentile : AbstractBase {
/// <summary>
/// Initializes the Percentile instance by clearing the buffer.
/// </summary>
public override void Init() {
public override void Init()
{
base.Init();
_buffer.Clear();
}
@@ -61,8 +67,10 @@ public class Percentile : AbstractBase {
/// Manages the state of the Percentile instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew) {
if (isNew) {
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
@@ -80,12 +88,14 @@ public class Percentile : AbstractBase {
/// as an approximation. Once the period is reached, it calculates the true percentile by
/// sorting the values and interpolating as necessary.
/// </remarks>
protected override double Calculation() {
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
double result;
if (_buffer.Count >= Period) {
if (_buffer.Count >= Period)
{
var values = _buffer.GetSpan().ToArray();
Array.Sort(values);
@@ -93,16 +103,21 @@ public class Percentile : AbstractBase {
int lowerIndex = (int)Math.Floor(position);
int upperIndex = (int)Math.Ceiling(position);
if (lowerIndex == upperIndex) {
if (lowerIndex == upperIndex)
{
result = values[lowerIndex];
} else {
}
else
{
// Interpolate between the two nearest values
double lowerValue = values[lowerIndex];
double upperValue = values[upperIndex];
double fraction = position - lowerIndex;
result = lowerValue + (upperValue - lowerValue) * fraction;
}
} else {
}
else
{
// Use average for insufficient data, like the Median class
result = _buffer.Average();
}
+22 -11
View File
@@ -10,7 +10,8 @@ namespace QuanTAlib;
/// for sample skewness calculation. A minimum of 3 data points is required for the
/// calculation.
/// </remarks>
public class Skew : AbstractBase {
public class Skew : AbstractBase
{
private readonly int Period;
private readonly CircularBuffer _buffer;
@@ -21,8 +22,10 @@ public class Skew : AbstractBase {
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 3.
/// </exception>
public Skew(int period) : base() {
if (period < 3) {
public Skew(int period)
{
if (period < 3)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 3 for skewness calculation.");
}
Period = period;
@@ -37,7 +40,8 @@ public class Skew : AbstractBase {
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the skewness.</param>
public Skew(object source, int period) : this(period) {
public Skew(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
@@ -45,7 +49,8 @@ public class Skew : AbstractBase {
/// <summary>
/// Initializes the Skew instance by clearing the buffer.
/// </summary>
public override void Init() {
public override void Init()
{
base.Init();
_buffer.Clear();
}
@@ -54,8 +59,10 @@ public class Skew : AbstractBase {
/// Manages the state of the Skew instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew) {
if (isNew) {
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
@@ -73,13 +80,15 @@ public class Skew : AbstractBase {
/// calculation. If there are fewer than 3 data points, or if the standard
/// deviation is zero, the method returns 0.
/// </remarks>
protected override double Calculation() {
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
double skew = 0;
if (_buffer.Count >= 3) { // We need at least 3 data points for skewness
if (_buffer.Count >= 3)
{ // We need at least 3 data points for skewness
var values = _buffer.GetSpan().ToArray();
double mean = values.Average();
double n = values.Length;
@@ -87,7 +96,8 @@ public class Skew : AbstractBase {
double sumCubedDeviations = 0;
double sumSquaredDeviations = 0;
foreach (var value in values) {
foreach (var value in values)
{
double deviation = value - mean;
sumCubedDeviations += Math.Pow(deviation, 3);
sumSquaredDeviations += Math.Pow(deviation, 2);
@@ -98,7 +108,8 @@ public class Skew : AbstractBase {
double m2 = sumSquaredDeviations / n;
double s3 = Math.Pow(m2, 1.5);
if (s3 != 0) { // Avoid division by zero
if (s3 != 0)
{ // Avoid division by zero
skew = (Math.Sqrt(n * (n - 1)) / (n - 2)) * (m3 / s3);
}
}
+18 -9
View File
@@ -9,7 +9,8 @@ namespace QuanTAlib;
/// standard deviation based on the isPopulation parameter. It uses a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Stddev : AbstractBase {
public class Stddev : AbstractBase
{
private readonly int Period;
private readonly bool IsPopulation;
private readonly CircularBuffer _buffer;
@@ -25,8 +26,10 @@ public class Stddev : AbstractBase {
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 2.
/// </exception>
public Stddev(int period, bool isPopulation = false) : base() {
if (period < 2) {
public Stddev(int period, bool isPopulation = false)
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
}
Period = period;
@@ -46,7 +49,8 @@ public class Stddev : AbstractBase {
/// <param name="isPopulation">
/// A flag indicating whether to calculate population (true) or sample (false) standard deviation.
/// </param>
public Stddev(object source, int period, bool isPopulation = false) : this(period, isPopulation) {
public Stddev(object source, int period, bool isPopulation = false) : this(period, isPopulation)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
@@ -54,7 +58,8 @@ public class Stddev : AbstractBase {
/// <summary>
/// Initializes the Stddev instance by clearing the buffer.
/// </summary>
public override void Init() {
public override void Init()
{
base.Init();
_buffer.Clear();
}
@@ -63,8 +68,10 @@ public class Stddev : AbstractBase {
/// Manages the state of the Stddev instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew) {
if (isNew) {
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
@@ -83,13 +90,15 @@ public class Stddev : AbstractBase {
/// where x is each value, mean is the average of all values, and n is the number of values.
/// If there's only one value in the buffer, the method returns 0.
/// </remarks>
protected override double Calculation() {
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
double stddev = 0;
if (_buffer.Count > 1) {
if (_buffer.Count > 1)
{
var values = _buffer.GetSpan().ToArray();
double mean = values.Average();
double sumOfSquaredDifferences = values.Sum(x => Math.Pow(x - mean, 2));
+18 -9
View File
@@ -9,7 +9,8 @@ namespace QuanTAlib;
/// variance based on the isPopulation parameter. It uses a circular buffer
/// to efficiently manage the data points within the specified period.
/// </remarks>
public class Variance : AbstractBase {
public class Variance : AbstractBase
{
private readonly int Period;
private readonly bool IsPopulation;
private readonly CircularBuffer _buffer;
@@ -25,8 +26,10 @@ public class Variance : AbstractBase {
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 2.
/// </exception>
public Variance(int period, bool isPopulation = false) : base() {
if (period < 2) {
public Variance(int period, bool isPopulation = false)
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2.");
}
Period = period;
@@ -46,7 +49,8 @@ public class Variance : AbstractBase {
/// <param name="isPopulation">
/// A flag indicating whether to calculate population (true) or sample (false) variance.
/// </param>
public Variance(object source, int period, bool isPopulation = false) : this(period, isPopulation) {
public Variance(object source, int period, bool isPopulation = false) : this(period, isPopulation)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
@@ -54,7 +58,8 @@ public class Variance : AbstractBase {
/// <summary>
/// Initializes the Variance instance by clearing the buffer.
/// </summary>
public override void Init() {
public override void Init()
{
base.Init();
_buffer.Clear();
}
@@ -63,8 +68,10 @@ public class Variance : AbstractBase {
/// Manages the state of the Variance instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew) {
if (isNew) {
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
@@ -83,13 +90,15 @@ public class Variance : AbstractBase {
/// where x is each value, mean is the average of all values, and n is the number of values.
/// If there's only one value in the buffer, the method returns 0.
/// </remarks>
protected override double Calculation() {
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
double variance = 0;
if (_buffer.Count > 1) {
if (_buffer.Count > 1)
{
var values = _buffer.GetSpan().ToArray();
double mean = values.Average();
double sumOfSquaredDifferences = values.Sum(x => Math.Pow(x - mean, 2));
+20 -10
View File
@@ -9,7 +9,8 @@ namespace QuanTAlib;
/// the most recent value in a given period. It uses a circular buffer to
/// efficiently manage the data points within the specified period.
/// </remarks>
public class Zscore : AbstractBase {
public class Zscore : AbstractBase
{
private readonly int Period;
private readonly CircularBuffer _buffer;
@@ -20,8 +21,10 @@ public class Zscore : AbstractBase {
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown when period is less than 2.
/// </exception>
public Zscore(int period) : base() {
if (period < 2) {
public Zscore(int period)
{
if (period < 2)
{
throw new ArgumentOutOfRangeException(nameof(period), "Period must be greater than or equal to 2 for Z-score calculation.");
}
Period = period;
@@ -36,7 +39,8 @@ public class Zscore : AbstractBase {
/// </summary>
/// <param name="source">The source object to subscribe to for value updates.</param>
/// <param name="period">The period over which to calculate the Z-score.</param>
public Zscore(object source, int period) : this(period) {
public Zscore(object source, int period) : this(period)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
@@ -44,7 +48,8 @@ public class Zscore : AbstractBase {
/// <summary>
/// Initializes the Zscore instance by clearing the buffer.
/// </summary>
public override void Init() {
public override void Init()
{
base.Init();
_buffer.Clear();
}
@@ -53,8 +58,10 @@ public class Zscore : AbstractBase {
/// Manages the state of the Zscore instance based on whether a new value is being processed.
/// </summary>
/// <param name="isNew">Indicates whether the current input is a new value.</param>
protected override void ManageState(bool isNew) {
if (isNew) {
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
@@ -72,13 +79,15 @@ public class Zscore : AbstractBase {
/// where x is the input value, μ is the mean of the period, and σ is the sample standard deviation.
/// If there are fewer than 2 data points or if the standard deviation is 0, the method returns 0.
/// </remarks>
protected override double Calculation() {
protected override double Calculation()
{
ManageState(Input.IsNew);
_buffer.Add(Input.Value, Input.IsNew);
double zScore = 0;
if (_buffer.Count >= 2) { // We need at least 2 data points for Z-score
if (_buffer.Count >= 2)
{ // We need at least 2 data points for Z-score
var values = _buffer.GetSpan().ToArray();
double mean = values.Average();
double n = values.Length;
@@ -86,7 +95,8 @@ public class Zscore : AbstractBase {
double sumSquaredDeviations = values.Sum(x => Math.Pow(x - mean, 2));
double standardDeviation = Math.Sqrt(sumSquaredDeviations / (n - 1)); // Sample standard deviation
if (standardDeviation != 0) { // Avoid division by zero
if (standardDeviation != 0)
{ // Avoid division by zero
zScore = (Input.Value - mean) / standardDeviation;
}
}