mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-18 18:48:05 +00:00
Merge branch 'dev' into main
This commit is contained in:
@@ -9,7 +9,7 @@ Statistical tools applied to price and returns. These indicators quantify relati
|
||||
| [BETA](beta/Beta.md) | Beta Coefficient | Asset volatility relative to market. β=1 means market-matched risk. |
|
||||
| [CMA](cma/Cma.md) | Cumulative Moving Average | Running average of all values. Welford's algorithm. No window. |
|
||||
| [COINTEGRATION](cointegration/Cointegration.md) | Cointegration | Tests if series share long-term equilibrium. Pairs trading foundation. |
|
||||
| [CORRELATION](correlation/Correlation.md) | Correlation | Linear relationship between two variables. Range: -1 to +1. |
|
||||
| [CORREL](correl/Correl.md) | Correlation | Linear relationship between two variables. Range: -1 to +1. |
|
||||
| [COVARIANCE](covariance/Covariance.md) | Covariance | Joint variability of two random variables. Building block for β. |
|
||||
| [ENTROPY](entropy/Entropy.md) | Shannon Entropy | Measures uncertainty/randomness. Higher entropy = less predictable. |
|
||||
| [GEOMEAN](geomean/Geomean.md) | Geometric Mean | nth root of product. Use for growth rates and ratios. |
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
| **PineScript** | [acf.pine](acf.pine) |
|
||||
|
||||
- The Autocorrelation Function (ACF) measures the correlation of a time series with a lagged copy of itself.
|
||||
- **Similar:** [PACF](../pacf/Pacf.md), [Correlation](../correlation/Correlation.md) | **Trading note:** Autocorrelation function; detects mean-reversion (negative ACF) vs momentum (positive ACF) in returns.
|
||||
- **Similar:** [PACF](../pacf/Pacf.md), [Correl](../correl/Correl.md) | **Trading note:** Autocorrelation function; detects mean-reversion (negative ACF) vs momentum (positive ACF) in returns.
|
||||
- Validated against mathematical properties and theoretical AR-process expectations.
|
||||
|
||||
The Autocorrelation Function (ACF) measures the correlation of a time series with a lagged copy of itself. It is fundamental for identifying repeating patterns, seasonal effects, and determining the order of time series models like ARMA/ARIMA.
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
| **PineScript** | [adf.pine](adf.pine) |
|
||||
|
||||
- Tests the null hypothesis that a time series contains a unit root (non-stationary). Output near **0** → stationary; output near **1** → unit root.
|
||||
- **Similar:** [Hurst](../hurst/Hurst.md), [Cointegration](../cointegration/Cointegration.md) | **Complementary:** Z-Score, Variance | **Trading note:** ADF < 0.05 confirms mean-reversion suitability.
|
||||
- **Similar indicators:** [Hurst](../hurst/Hurst.md), [Cointegration](../cointegration/Cointegration.md)
|
||||
- **Complementary indicators:** [Z-Score](../zscore/Zscore.md), [Variance](../variance/Variance.md)
|
||||
- **Trading note:** ADF < 0.05 confirms mean-reversion suitability.
|
||||
- Validated against Python `statsmodels.tsa.stattools.adfuller` reference implementation.
|
||||
|
||||
The Augmented Dickey-Fuller test is the gold standard for detecting whether a financial time series is stationary or contains a unit root. Unlike the original Dickey-Fuller test, the augmented version includes lagged difference terms $\Delta y_{t-i}$ to absorb serial correlation, ensuring the test statistic follows the correct distribution. The p-value output uses MacKinnon (1994, 2010) polynomial interpolation with a standard normal CDF approximation, providing machine-precision results without lookup tables.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
| **PineScript** | [beta.pine](beta.pine) |
|
||||
|
||||
- Beta measures the volatility of an asset in relation to the overall market.
|
||||
- **Similar:** [Correlation](../correlation/Correlation.md), [Covariance](../covariance/Covariance.md) | **Trading note:** Beta coefficient; measures systematic risk vs benchmark. β>1 = amplifies market moves.
|
||||
- **Similar:** [Correl](../correl/Correl.md), [Covariance](../covariance/Covariance.md) | **Trading note:** Beta coefficient; measures systematic risk vs benchmark. β>1 = amplifies market moves.
|
||||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||||
|
||||
Beta measures the volatility of an asset in relation to the overall market. It's the slope of the regression line between the asset's returns and the market's returns. A beta of 1.0 means the asset moves in lockstep with the market. A beta of 2.0 means the asset is twice as volatile as the market.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
| **PineScript** | [cointegration.pine](cointegration.pine) |
|
||||
|
||||
- The Cointegration indicator measures the long-run equilibrium relationship between two price series using the Engle-Granger two-step method with an...
|
||||
- **Similar:** [Correlation](../correlation/Correlation.md), [Granger](../granger/Granger.md) | **Trading note:** Tests if two series share a long-run equilibrium. Foundation of statistical arbitrage (pairs trading).
|
||||
- **Similar:** [Correl](../correl/Correl.md), [Granger](../granger/Granger.md) | **Trading note:** Tests if two series share a long-run equilibrium. Foundation of statistical arbitrage (pairs trading).
|
||||
- Validated against TradingView PineScript reference and statistical property tests.
|
||||
|
||||
The Cointegration indicator measures the long-run equilibrium relationship between two price series using the Engle-Granger two-step method with an Augmented Dickey-Fuller (ADF) test. Unlike correlation, which measures short-term co-movement, cointegration tests whether two non-stationary series share a common stochastic trend—meaning they may diverge temporarily but are statistically bound to revert to their equilibrium relationship.
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace QuanTAlib;
|
||||
/// - |r| < 0.3: Weak correlation
|
||||
/// </remarks>
|
||||
[SkipLocalsInit]
|
||||
public sealed class Correlation : AbstractBase
|
||||
public sealed class Correl : AbstractBase
|
||||
{
|
||||
private readonly RingBuffer _bufferX;
|
||||
private readonly RingBuffer _bufferY;
|
||||
@@ -58,10 +58,10 @@ public sealed class Correlation : AbstractBase
|
||||
public override bool IsHot => _bufferX.Count >= WarmupPeriod;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Correlation indicator.
|
||||
/// Creates a new Correl indicator.
|
||||
/// </summary>
|
||||
/// <param name="period">Lookback period for calculation (must be > 1)</param>
|
||||
public Correlation(int period = 20)
|
||||
public Correl(int period = 20)
|
||||
{
|
||||
if (period <= 1)
|
||||
{
|
||||
@@ -71,7 +71,7 @@ public sealed class Correlation : AbstractBase
|
||||
_bufferX = new RingBuffer(period);
|
||||
_bufferY = new RingBuffer(period);
|
||||
|
||||
Name = $"Correlation({period})";
|
||||
Name = $"Correl({period})";
|
||||
WarmupPeriod = period;
|
||||
}
|
||||
|
||||
@@ -118,7 +118,7 @@ public sealed class Correlation : AbstractBase
|
||||
ProcessBarCorrection(x, y);
|
||||
}
|
||||
|
||||
double correlation = CalculateCorrelation();
|
||||
double correlation = CalculateCorrel();
|
||||
|
||||
Last = new TValue(seriesX.Time, correlation);
|
||||
PubEvent(Last);
|
||||
@@ -143,13 +143,13 @@ public sealed class Correlation : AbstractBase
|
||||
/// <remarks>Not supported for bi-input indicator. Use Update(seriesX, seriesY) instead.</remarks>
|
||||
public override TValue Update(TValue input, bool isNew = true)
|
||||
{
|
||||
throw new NotSupportedException("Correlation requires two inputs (seriesX and seriesY). Use Update(seriesX, seriesY).");
|
||||
throw new NotSupportedException("Correl requires two inputs (seriesX and seriesY). Use Update(seriesX, seriesY).");
|
||||
}
|
||||
/// <summary>Not supported. This indicator requires two inputs; use <see cref="Batch(TSeries, TSeries, int)"/> instead.</summary>
|
||||
/// <remarks>Not supported for bi-input indicator. Use Calculate(seriesX, seriesY, period) instead.</remarks>
|
||||
public override TSeries Update(TSeries source)
|
||||
{
|
||||
throw new NotSupportedException("Correlation requires two inputs. Use Batch(seriesX, seriesY, period).");
|
||||
throw new NotSupportedException("Correl requires two inputs. Use Batch(seriesX, seriesY, period).");
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
@@ -316,7 +316,7 @@ public sealed class Correlation : AbstractBase
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private double CalculateCorrelation()
|
||||
private double CalculateCorrel()
|
||||
{
|
||||
int n = _bufferX.Count;
|
||||
if (n < 2)
|
||||
@@ -355,7 +355,7 @@ public sealed class Correlation : AbstractBase
|
||||
/// <summary>Not supported. This indicator requires two input spans.</summary>
|
||||
public override void Prime(ReadOnlySpan<double> source, TimeSpan? step = null)
|
||||
{
|
||||
throw new NotSupportedException("Correlation requires two inputs.");
|
||||
throw new NotSupportedException("Correl requires two inputs.");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -414,7 +414,7 @@ public sealed class Correlation : AbstractBase
|
||||
throw new ArgumentException("Period must be greater than 1", nameof(period));
|
||||
}
|
||||
|
||||
var indicator = new Correlation(period);
|
||||
var indicator = new Correl(period);
|
||||
|
||||
for (int i = 0; i < seriesX.Length; i++)
|
||||
{
|
||||
@@ -426,14 +426,14 @@ public sealed class Correlation : AbstractBase
|
||||
/// <summary>
|
||||
/// Calculates Pearson correlation for two time series and returns both the result series and the live indicator instance.
|
||||
/// </summary>
|
||||
public static (TSeries Results, Correlation Indicator) Calculate(TSeries seriesX, TSeries seriesY, int period = 20)
|
||||
public static (TSeries Results, Correl Indicator) Calculate(TSeries seriesX, TSeries seriesY, int period = 20)
|
||||
{
|
||||
if (seriesX.Count != seriesY.Count)
|
||||
{
|
||||
throw new ArgumentException("Series must have the same length", nameof(seriesY));
|
||||
}
|
||||
|
||||
var indicator = new Correlation(period);
|
||||
var indicator = new Correl(period);
|
||||
var result = new TSeries(seriesX.Count);
|
||||
|
||||
var timesX = seriesX.Times;
|
||||
@@ -10,7 +10,7 @@
|
||||
| **Outputs** | Single series (Pearson r) |
|
||||
| **Output range** | Varies (see docs) |
|
||||
| **Warmup** | `period` bars |
|
||||
| **PineScript** | [correlation.pine](correlation.pine) |
|
||||
| **PineScript** | [correl.pine](correl.pine) |
|
||||
|
||||
- The Pearson Correlation Coefficient measures the linear relationship between two variables, returning a value from -1 (perfect negative correlation...
|
||||
- **Similar:** [Spearman](../spearman/Spearman.md), [Kendall](../kendall/Kendall.md) | **Trading note:** Pearson correlation; measures linear relationship strength. Used for portfolio diversification and pairs trading.
|
||||
@@ -189,7 +189,7 @@ Monitor correlation stability:
|
||||
### Streaming Mode (Bi-Input)
|
||||
|
||||
```csharp
|
||||
var corr = new Correlation(period: 20);
|
||||
var corr = new Correl(period: 20);
|
||||
foreach (var (priceA, priceB) in pricePairs)
|
||||
{
|
||||
var result = corr.Update(priceA, priceB);
|
||||
@@ -206,7 +206,7 @@ foreach (var (priceA, priceB) in pricePairs)
|
||||
var seriesA = new TSeries();
|
||||
var seriesB = new TSeries();
|
||||
// ... populate series ...
|
||||
var results = Correlation.Calculate(seriesA, seriesB, period: 20);
|
||||
var results = Correl.Calculate(seriesA, seriesB, period: 20);
|
||||
```
|
||||
|
||||
### Span Mode (Zero Allocation)
|
||||
@@ -216,13 +216,13 @@ double[] pricesA = new double[1000];
|
||||
double[] pricesB = new double[1000];
|
||||
double[] output = new double[1000];
|
||||
// ... populate inputs ...
|
||||
Correlation.Batch(pricesA.AsSpan(), pricesB.AsSpan(), output.AsSpan(), period: 20);
|
||||
Correl.Batch(pricesA.AsSpan(), pricesB.AsSpan(), output.AsSpan(), period: 20);
|
||||
```
|
||||
|
||||
### Bar Correction Support
|
||||
|
||||
```csharp
|
||||
var corr = new Correlation(20);
|
||||
var corr = new Correl(20);
|
||||
|
||||
// New bar
|
||||
corr.Update(100.0, 50.0, isNew: true); // r = 0.85
|
||||
@@ -1,7 +1,7 @@
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// © mihakralj
|
||||
//@version=6
|
||||
indicator("Pearson's Correlation (CORRELATION)", "CORRELATION", overlay=false)
|
||||
indicator("Pearson's Correlation (CORREL)", "CORREL", overlay=false)
|
||||
|
||||
//@function Calculates Pearson correlation coefficient using single pass with circular buffer
|
||||
//@param src1 series float First series to analyze
|
||||
+35
-35
@@ -1,42 +1,42 @@
|
||||
namespace QuanTAlib.Tests;
|
||||
|
||||
public class CorrelationTests
|
||||
public class CorrelTests
|
||||
{
|
||||
[Fact]
|
||||
public void Constructor_ValidPeriod_CreatesIndicator()
|
||||
{
|
||||
var indicator = new Correlation(20);
|
||||
Assert.Equal("Correlation(20)", indicator.Name);
|
||||
var indicator = new Correl(20);
|
||||
Assert.Equal("Correl(20)", indicator.Name);
|
||||
Assert.Equal(20, indicator.WarmupPeriod);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_MinimumValidPeriod_CreatesIndicator()
|
||||
{
|
||||
var indicator = new Correlation(2);
|
||||
Assert.Equal("Correlation(2)", indicator.Name);
|
||||
var indicator = new Correl(2);
|
||||
Assert.Equal("Correl(2)", indicator.Name);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_InvalidPeriod_ThrowsArgumentException()
|
||||
{
|
||||
Assert.Throws<ArgumentException>(() => new Correlation(1));
|
||||
Assert.Throws<ArgumentException>(() => new Correlation(0));
|
||||
Assert.Throws<ArgumentException>(() => new Correlation(-5));
|
||||
Assert.Throws<ArgumentException>(() => new Correl(1));
|
||||
Assert.Throws<ArgumentException>(() => new Correl(0));
|
||||
Assert.Throws<ArgumentException>(() => new Correl(-5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Update_SingleValue_ReturnsNaN()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
var result = indicator.Update(100.0, 200.0, true);
|
||||
Assert.True(double.IsNaN(result.Value));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Update_TwoValues_ReturnsValidCorrelation()
|
||||
public void Update_TwoValues_ReturnsValidCorrel()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
indicator.Update(100.0, 200.0, true);
|
||||
var result = indicator.Update(102.0, 204.0, true);
|
||||
Assert.True(double.IsFinite(result.Value));
|
||||
@@ -45,7 +45,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Update_PerfectPositiveCorrelation_ReturnsOne()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
|
||||
// Same values scaled by constant should give correlation = 1
|
||||
for (int i = 0; i < 10; i++)
|
||||
@@ -62,7 +62,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Update_PerfectNegativeCorrelation_ReturnsMinusOne()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
|
||||
// Opposite movements should give correlation = -1
|
||||
for (int i = 0; i < 10; i++)
|
||||
@@ -79,7 +79,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Update_ConstantValues_ReturnsNaN()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
|
||||
// Constant values have zero variance, so correlation is undefined
|
||||
for (int i = 0; i < 10; i++)
|
||||
@@ -93,8 +93,8 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Update_BarCorrection_RestoresState()
|
||||
{
|
||||
var indicator1 = new Correlation(5);
|
||||
var indicator2 = new Correlation(5);
|
||||
var indicator1 = new Correl(5);
|
||||
var indicator2 = new Correl(5);
|
||||
|
||||
// Feed same initial data
|
||||
for (int i = 0; i < 10; i++)
|
||||
@@ -119,8 +119,8 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Update_IterativeCorrections_Restore()
|
||||
{
|
||||
var corrected = new Correlation(5);
|
||||
var direct = new Correlation(5);
|
||||
var corrected = new Correl(5);
|
||||
var direct = new Correl(5);
|
||||
|
||||
// Feed identical initial state
|
||||
for (int i = 0; i < 8; i++)
|
||||
@@ -151,7 +151,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Update_NaNInput_UsesLastValidValue()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
|
||||
// Add valid data
|
||||
for (int i = 0; i < 5; i++)
|
||||
@@ -169,7 +169,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Update_InfinityInput_UsesLastValidValue()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
|
||||
// Add valid data
|
||||
for (int i = 0; i < 5; i++)
|
||||
@@ -185,7 +185,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void IsHot_BelowPeriod_ReturnsFalse()
|
||||
{
|
||||
var indicator = new Correlation(10);
|
||||
var indicator = new Correl(10);
|
||||
indicator.Update(100.0, 200.0, true);
|
||||
Assert.False(indicator.IsHot);
|
||||
}
|
||||
@@ -193,7 +193,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void IsHot_AtPeriod_ReturnsTrue()
|
||||
{
|
||||
var indicator = new Correlation(10);
|
||||
var indicator = new Correl(10);
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
indicator.Update(100.0 + i, 200.0 + i, true);
|
||||
@@ -204,7 +204,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Reset_ClearsState()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
|
||||
// Add data
|
||||
for (int i = 0; i < 10; i++)
|
||||
@@ -224,14 +224,14 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Update_TValue_ThrowsNotSupportedException()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
Assert.Throws<NotSupportedException>(() => indicator.Update(new TValue(DateTime.UtcNow, 100.0)));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Update_TSeries_ThrowsNotSupportedException()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
var series = new TSeries(10);
|
||||
Assert.Throws<NotSupportedException>(() => indicator.Update(series));
|
||||
}
|
||||
@@ -239,7 +239,7 @@ public class CorrelationTests
|
||||
[Fact]
|
||||
public void Prime_ThrowsNotSupportedException()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
Assert.Throws<NotSupportedException>(() => indicator.Prime(new double[] { 1, 2, 3 }));
|
||||
}
|
||||
|
||||
@@ -255,7 +255,7 @@ public class CorrelationTests
|
||||
seriesY.Add(new TValue(DateTime.UtcNow.AddMinutes(i), 200.0 + (i * 2)));
|
||||
}
|
||||
|
||||
var result = Correlation.Batch(seriesX, seriesY, 5);
|
||||
var result = Correl.Batch(seriesX, seriesY, 5);
|
||||
|
||||
Assert.Equal(20, result.Count);
|
||||
}
|
||||
@@ -275,7 +275,7 @@ public class CorrelationTests
|
||||
seriesY.Add(new TValue(DateTime.UtcNow.AddMinutes(i), 200.0 + i));
|
||||
}
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Correlation.Batch(seriesX, seriesY, 5));
|
||||
Assert.Throws<ArgumentException>(() => Correl.Batch(seriesX, seriesY, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -291,7 +291,7 @@ public class CorrelationTests
|
||||
seriesY[i] = 200.0 + (i * 2);
|
||||
}
|
||||
|
||||
Correlation.Batch(seriesX, seriesY, output, 5);
|
||||
Correl.Batch(seriesX, seriesY, output, 5);
|
||||
|
||||
// First value should be NaN (not enough data)
|
||||
Assert.True(double.IsNaN(output[0]));
|
||||
@@ -307,7 +307,7 @@ public class CorrelationTests
|
||||
double[] seriesY = new double[15];
|
||||
double[] output = new double[10];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Correlation.Batch(seriesX, seriesY, output, 5));
|
||||
Assert.Throws<ArgumentException>(() => Correl.Batch(seriesX, seriesY, output, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -317,7 +317,7 @@ public class CorrelationTests
|
||||
double[] seriesY = new double[20];
|
||||
double[] output = new double[10];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Correlation.Batch(seriesX, seriesY, output, 5));
|
||||
Assert.Throws<ArgumentException>(() => Correl.Batch(seriesX, seriesY, output, 5));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
@@ -327,13 +327,13 @@ public class CorrelationTests
|
||||
double[] seriesY = new double[20];
|
||||
double[] output = new double[20];
|
||||
|
||||
Assert.Throws<ArgumentException>(() => Correlation.Batch(seriesX, seriesY, output, 1));
|
||||
Assert.Throws<ArgumentException>(() => Correl.Batch(seriesX, seriesY, output, 1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void CorrelationRange_AlwaysBetweenMinusOneAndOne()
|
||||
{
|
||||
var indicator = new Correlation(10);
|
||||
var indicator = new Correl(10);
|
||||
var gbmX = new GBM(startPrice: 100, mu: 0.02, sigma: 0.3, seed: 12345);
|
||||
var gbmY = new GBM(startPrice: 200, mu: 0.01, sigma: 0.5, seed: 54321);
|
||||
|
||||
@@ -369,7 +369,7 @@ public class CorrelationTests
|
||||
}
|
||||
|
||||
// Streaming calculation
|
||||
var indicator = new Correlation(period);
|
||||
var indicator = new Correl(period);
|
||||
double[] streamingResults = new double[length];
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
@@ -378,7 +378,7 @@ public class CorrelationTests
|
||||
|
||||
// Batch calculation
|
||||
double[] batchResults = new double[length];
|
||||
Correlation.Batch(seriesX, seriesY, batchResults, period);
|
||||
Correl.Batch(seriesX, seriesY, batchResults, period);
|
||||
|
||||
// Compare last 50 values (after warmup)
|
||||
for (int i = length - 50; i < length; i++)
|
||||
+38
-38
@@ -8,13 +8,13 @@ namespace QuanTAlib.Tests;
|
||||
/// Validation tests for Correlation (Pearson Correlation Coefficient) indicator.
|
||||
/// Validates against Skender.Stock.Indicators.GetCorrelation and mathematical properties.
|
||||
/// </summary>
|
||||
public sealed class CorrelationValidationTests : IDisposable
|
||||
public sealed class CorrelValidationTests : IDisposable
|
||||
{
|
||||
private const double Tolerance = 1e-10;
|
||||
private readonly ValidationTestData _data;
|
||||
private readonly ITestOutputHelper _output;
|
||||
|
||||
public CorrelationValidationTests(ITestOutputHelper output)
|
||||
public CorrelValidationTests(ITestOutputHelper output)
|
||||
{
|
||||
_data = new ValidationTestData();
|
||||
_output = output;
|
||||
@@ -29,7 +29,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
#region External Library Validation — Skender
|
||||
|
||||
[Fact]
|
||||
public void Validate_Skender_Correlation()
|
||||
public void Validate_Skender_Correl()
|
||||
{
|
||||
// === DESCRIPTION ===
|
||||
// Compares QuanTAlib Correlation against Skender.Stock.Indicators.GetCorrelation
|
||||
@@ -65,7 +65,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
var sResult = quotesA.GetCorrelation(quotesB, period).ToList();
|
||||
|
||||
// --- QuanTAlib: streaming API ---
|
||||
var corr = new Correlation(period);
|
||||
var corr = new Correl(period);
|
||||
var qValues = new List<double>();
|
||||
|
||||
for (int i = 0; i < _data.Count; i++)
|
||||
@@ -126,7 +126,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
{
|
||||
var sResult = _data.SkenderQuotes.GetCorrelation(quotesB, period).ToList();
|
||||
|
||||
var corr = new Correlation(period);
|
||||
var corr = new Correl(period);
|
||||
int matched = 0;
|
||||
|
||||
for (int i = 0; i < _data.Count; i++)
|
||||
@@ -175,7 +175,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
|
||||
var sResult = quotesA.GetCorrelation(quotesB, period).ToList();
|
||||
|
||||
var corr = new Correlation(period);
|
||||
var corr = new Correl(period);
|
||||
int matched = 0;
|
||||
|
||||
for (int i = 0; i < _data.Count; i++)
|
||||
@@ -207,7 +207,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
public void Correlation_PerfectLinearPositive_ReturnsOne()
|
||||
{
|
||||
// y = a + b*x with b > 0 should give r = 1
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
@@ -223,7 +223,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
public void Correlation_PerfectLinearNegative_ReturnsMinusOne()
|
||||
{
|
||||
// y = a + b*x with b < 0 should give r = -1
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
@@ -238,9 +238,9 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_SymmetryProperty_XY_Equals_YX()
|
||||
{
|
||||
// Correlation(X, Y) should equal Correlation(Y, X)
|
||||
var indicatorXY = new Correlation(10);
|
||||
var indicatorYX = new Correlation(10);
|
||||
// Correl(X, Y) should equal Correl(Y, X)
|
||||
var indicatorXY = new Correl(10);
|
||||
var indicatorYX = new Correl(10);
|
||||
var gbmX = new GBM(startPrice: 100, mu: 0.02, sigma: 0.2, seed: 12345);
|
||||
var gbmY = new GBM(startPrice: 50, mu: 0.01, sigma: 0.15, seed: 54321);
|
||||
|
||||
@@ -260,8 +260,8 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
{
|
||||
// Correlation is invariant under positive linear transformations
|
||||
// corr(X, Y) = corr(aX + b, cY + d) when a, c > 0
|
||||
var indicator1 = new Correlation(10);
|
||||
var indicator2 = new Correlation(10);
|
||||
var indicator1 = new Correl(10);
|
||||
var indicator2 = new Correl(10);
|
||||
var gbmX = new GBM(startPrice: 100, mu: 0.02, sigma: 0.2, seed: 12345);
|
||||
var gbmY = new GBM(startPrice: 50, mu: 0.01, sigma: 0.15, seed: 54321);
|
||||
|
||||
@@ -283,7 +283,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
public void Correlation_BoundedProperty_AlwaysBetweenMinusOneAndOne()
|
||||
{
|
||||
// Correlation coefficient is always in [-1, 1]
|
||||
var indicator = new Correlation(10);
|
||||
var indicator = new Correl(10);
|
||||
var gbmX = new GBM(startPrice: 100, mu: 0.1, sigma: 0.5, seed: 12345);
|
||||
var gbmY = new GBM(startPrice: 50, mu: -0.05, sigma: 0.3, seed: 54321);
|
||||
|
||||
@@ -304,7 +304,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
public void Correlation_ZeroVariance_ReturnsNaN()
|
||||
{
|
||||
// When one or both series have zero variance, correlation is undefined
|
||||
var indicator = new Correlation(10);
|
||||
var indicator = new Correl(10);
|
||||
|
||||
for (int i = 0; i < 20; i++)
|
||||
{
|
||||
@@ -332,7 +332,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
// r = Cov(X,Y) / sqrt(Var(X) * Var(Y)) = 1.2 / sqrt(2 * 1.2) = 1.2 / sqrt(2.4)
|
||||
// = 1.2 / 1.5492 ≈ 0.7746
|
||||
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
double[] x = [1, 2, 3, 4, 5];
|
||||
double[] y = [2, 4, 5, 4, 5];
|
||||
|
||||
@@ -346,11 +346,11 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Correlation_KnownValues_NoCorrelation()
|
||||
public void Correlation_KnownValues_NoCorrel()
|
||||
{
|
||||
// X = [1, 2, 3, 4, 5], Y = [3, 3, 3, 3, 3] (constant)
|
||||
// Should be NaN (or 0 with special handling)
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
double[] x = [1, 2, 3, 4, 5];
|
||||
double[] y = [3, 3, 3, 3, 3];
|
||||
|
||||
@@ -383,10 +383,10 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
}
|
||||
|
||||
// Batch calculation
|
||||
var batchResult = Correlation.Batch(seriesX, seriesY, 20);
|
||||
var batchResult = Correl.Batch(seriesX, seriesY, 20);
|
||||
|
||||
// Streaming calculation
|
||||
var streamingIndicator = new Correlation(20);
|
||||
var streamingIndicator = new Correl(20);
|
||||
for (int i = 0; i < seriesX.Count; i++)
|
||||
{
|
||||
streamingIndicator.Update(seriesX[i].Value, seriesY[i].Value);
|
||||
@@ -420,10 +420,10 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
}
|
||||
|
||||
// Span calculation
|
||||
Correlation.Batch(seriesX, seriesY, output, 20);
|
||||
Correl.Batch(seriesX, seriesY, output, 20);
|
||||
|
||||
// Streaming calculation
|
||||
var streamingIndicator = new Correlation(20);
|
||||
var streamingIndicator = new Correl(20);
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
streamingIndicator.Update(seriesX[i], seriesY[i]);
|
||||
@@ -443,7 +443,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_ResetProducesSameResults()
|
||||
{
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
var gbmX = new GBM(startPrice: 100, mu: 0.02, sigma: 0.2, seed: 12345);
|
||||
var gbmY = new GBM(startPrice: 50, mu: 0.01, sigma: 0.15, seed: 54321);
|
||||
|
||||
@@ -475,7 +475,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_SlidingWindow_MovesCorrectly()
|
||||
{
|
||||
var indicator = new Correlation(5);
|
||||
var indicator = new Correl(5);
|
||||
|
||||
// Build up with known values for period 5
|
||||
// After 5 values, window should be full
|
||||
@@ -501,7 +501,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_SlidingWindow_DropsOldValues()
|
||||
{
|
||||
var indicator = new Correlation(3);
|
||||
var indicator = new Correl(3);
|
||||
|
||||
// First window: perfectly correlated
|
||||
indicator.Update(1, 2);
|
||||
@@ -522,7 +522,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_LargeValues_MaintainsStability()
|
||||
{
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
@@ -538,7 +538,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_SmallValues_MaintainsStability()
|
||||
{
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
|
||||
// Use values that are small but not so small they cause numerical issues
|
||||
for (int i = 0; i < 50; i++)
|
||||
@@ -555,7 +555,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_MixedMagnitudes_HandlesCorrectly()
|
||||
{
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
@@ -576,7 +576,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
public void Correlation_HighPositiveCorrelation_DetectedCorrectly()
|
||||
{
|
||||
// Create two series with high positive correlation (r ≈ 0.95+)
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
|
||||
// Use deterministic data that creates high correlation
|
||||
for (int i = 0; i < 100; i++)
|
||||
@@ -593,7 +593,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
public void Correlation_NegativeCorrelation_DetectedCorrectly()
|
||||
{
|
||||
// Create two series with negative correlation
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
var random = new GBM(startPrice: 100.0, sigma: 1.0, seed: 42);
|
||||
|
||||
for (int i = 0; i < 100; i++)
|
||||
@@ -612,7 +612,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
// Create two series with weak correlation: pure independent noise, no shared trend.
|
||||
// Use two independent GBMs (different seeds) and feed their incremental log-returns directly.
|
||||
// With period=20 and fully independent noise sequences, correlation should be near zero.
|
||||
var indicator = new Correlation(20);
|
||||
var indicator = new Correl(20);
|
||||
var gbmX = new GBM(startPrice: 100.0, sigma: 0.2, seed: 43);
|
||||
var gbmY = new GBM(startPrice: 100.0, sigma: 0.2, seed: 9871);
|
||||
var barsX = gbmX.Fetch(101, DateTime.UtcNow.Ticks, TimeSpan.FromMinutes(1));
|
||||
@@ -637,9 +637,9 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_DifferentPeriods_ProduceDifferentResults()
|
||||
{
|
||||
var indicator5 = new Correlation(5);
|
||||
var indicator20 = new Correlation(20);
|
||||
var indicator50 = new Correlation(50);
|
||||
var indicator5 = new Correl(5);
|
||||
var indicator20 = new Correl(20);
|
||||
var indicator50 = new Correl(50);
|
||||
var gbmX = new GBM(startPrice: 100, mu: 0.02, sigma: 0.2, seed: 12345);
|
||||
var gbmY = new GBM(startPrice: 50, mu: 0.01, sigma: 0.15, seed: 54321);
|
||||
|
||||
@@ -660,8 +660,8 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
[Fact]
|
||||
public void Correlation_SmallPeriod_MoreVolatile()
|
||||
{
|
||||
var indicator3 = new Correlation(3);
|
||||
var indicator30 = new Correlation(30);
|
||||
var indicator3 = new Correl(3);
|
||||
var indicator30 = new Correl(30);
|
||||
var gbmX = new GBM(startPrice: 100, mu: 0.02, sigma: 0.2, seed: 12345);
|
||||
var gbmY = new GBM(startPrice: 50, mu: 0.01, sigma: 0.15, seed: 54321);
|
||||
|
||||
@@ -732,7 +732,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
Assert.True(length > 100, $"TALib Correl produced only {length} values");
|
||||
|
||||
// QuanTAlib streaming
|
||||
var corr = new Correlation(period);
|
||||
var corr = new Correl(period);
|
||||
var qlValues = new double[_data.Count];
|
||||
for (int i = 0; i < _data.Count; i++)
|
||||
{
|
||||
@@ -770,7 +770,7 @@ public sealed class CorrelationValidationTests : IDisposable
|
||||
|
||||
(int offset, int length) = outRange.GetOffsetAndLength(taOut.Length);
|
||||
|
||||
var corr = new Correlation(period);
|
||||
var corr = new Correl(period);
|
||||
var qlValues = new double[_data.Count];
|
||||
for (int i = 0; i < _data.Count; i++)
|
||||
{
|
||||
@@ -13,7 +13,7 @@
|
||||
| **PineScript** | [covariance.pine](covariance.pine) |
|
||||
|
||||
- Covariance measures the joint variability of two random variables.
|
||||
- **Similar:** [Correlation](../correlation/Correlation.md), [Beta](../beta/Beta.md) | **Trading note:** Rolling covariance; measures how two assets move together. Foundation of portfolio theory.
|
||||
- **Similar:** [Correl](../correl/Correl.md), [Beta](../beta/Beta.md) | **Trading note:** Rolling covariance; measures how two assets move together. Foundation of portfolio theory.
|
||||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||||
|
||||
Covariance measures the joint variability of two random variables. It indicates the direction of the linear relationship between variables.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
| **PineScript** | [granger.pine](granger.pine) |
|
||||
|
||||
- The Granger Causality test asks a precise, falsifiable question: does knowing the history of series X improve your ability to predict series Y, bey...
|
||||
- **Similar:** [Cointegration](../cointegration/Cointegration.md), [Correlation](../correlation/Correlation.md) | **Trading note:** Granger causality test; determines if one time series can forecast another. Lead-lag detection.
|
||||
- **Similar:** [Cointegration](../cointegration/Cointegration.md), [Correl](../correl/Correl.md) | **Trading note:** Granger causality test; determines if one time series can forecast another. Lead-lag detection.
|
||||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||||
|
||||
## Introduction
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
| **PineScript** | [spearman.pine](spearman.pine) |
|
||||
|
||||
- Spearman's ρ (rho) measures the strength and direction of monotonic association between two variables.
|
||||
- **Similar:** [Correlation](../correlation/Correlation.md), [Kendall](../kendall/Kendall.md) | **Trading note:** Spearman rank correlation; non-parametric, detects monotonic (not just linear) relationships.
|
||||
- **Similar:** [Correl](../correl/Correl.md), [Kendall](../kendall/Kendall.md) | **Trading note:** Spearman rank correlation; non-parametric, detects monotonic (not just linear) relationships.
|
||||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||||
|
||||
Spearman's ρ (rho) measures the strength and direction of monotonic association between two variables. Unlike Pearson's correlation, which measures linear relationship, Spearman captures any monotonic relationship. A portfolio of stocks whose returns move monotonically together has different risk than one whose components merely share a linear trend. Spearman detects both.
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
| **PineScript** | [theil.pine](theil.pine) |
|
||||
|
||||
- The Theil T Index is an information-theoretic measure of inequality (or concentration) within a distribution of positive values.
|
||||
- **Similar:** [Correlation](../correlation/Correlation.md), [LinReg](../linreg/LinReg.md) | **Trading note:** Theil–Sen estimator; robust slope calculation using medians of pairwise slopes. Resistant to outliers.
|
||||
- **Similar:** [Correl](../correl/Correl.md), [LinReg](../linreg/LinReg.md) | **Trading note:** Theil–Sen estimator; robust slope calculation using medians of pairwise slopes. Resistant to outliers.
|
||||
- Validated against TA-Lib, Skender, and Tulip reference implementations where available.
|
||||
|
||||
## Introduction
|
||||
|
||||
Reference in New Issue
Block a user