This commit is contained in:
Miha
2024-11-10 11:11:38 -08:00
parent 770b1e0d27
commit 428611315e
9 changed files with 430 additions and 71 deletions
+4 -4
View File
@@ -8,9 +8,9 @@
| Momentum | 17 | 0 | 17 |
| Oscillators| 24 | 5 | 29 |
| Patterns | 0 | 8 | 8 |
| Statistics | 21 | 2 | 23 |
| Statistics | 22 | 1 | 23 |
| Volatility | 31 | 4 | 35 |
| Total | 126 | 19 | 145 |
| Total | 127 | 18 | 145 |
## Indicators by Category
@@ -110,12 +110,13 @@ RPP - Rolling Pivot Points (Support 1-3, Pivot, Resistance 1-3)
WF - Williams Fractal
ZZ - Zig Zag Pattern
### Statistics (21/23)
### Statistics (22/23)
✔️ BETA - Beta coefficient measuring volatility relative to market
✔️ CORR - Correlation coefficient between two series
✔️ COVAR - Covariance between two series
✔️ CURVATURE - Curvature of a time series
✔️ ENTROPY - Information entropy of a series
✔️ GRANGER - Granger causality test
✔️ HURST - Hurst exponent for trend strength
✔️ KENDALL - Kendall rank correlation
✔️ KURTOSIS - Kurtosis measuring tail extremity
@@ -133,7 +134,6 @@ ZZ - Zig Zag Pattern
✔️ VARIANCE - Statistical variance
✔️ ZSCORE - Z-score standardization
COINTEGRATION - Test for cointegrated series
GRANGER - Granger causality test
### Volatility (31/35)
✔️ ADR - Average Daily Range
+86
View File
@@ -0,0 +1,86 @@
# QuanTAlib Class Types by Input Requirements
## Two TValues Required
- Huber
- Mae
- Mapd
- Mape
- Mase
- Mda
- Me
- Mpe
- Mse
- Msle
- Rae
- Rmse
- Rmsle
- Rse
- Rsquared
- Smape
- Beta (asset vs market returns)
- Corr (correlation between two series)
- Covar (covariance between two series)
- Granger (Granger causality test)
- Kendall (Kendall rank correlation)
- Spearman (Spearman rank correlation)
- Theil (Theil's U statistic)
## One TValue Required
- Curvature
- Entropy
- Hurst
- Kurtosis
- Max
- Median
- Min
- Mode
- Percentile
- Skew
- Slope
- Stddev
- Tsf
- Variance
- Zscore
- Apo
- Dpo
- Macd
- Mom
- Pmo
- Po
- Ppo
- Roc
- Trix
- Vel
- Ac
- Ao
- Bop
- Cci
- Cfo
- Chop
- Cmo
- Cog
- Coppock
- Crsi
- Cti
- Dosc
- Efi
- Fisher
- Rsi
- Rsx
- Smi
- Srsi
- Stc
- Stoch
- Tsi
- Uo
- Willr
## One TBar Required
- Aroon (uses high/low)
- Vortex (uses high/low/close)
## Two TBars Required
- Adx (requires two bars for true range calculation)
- Adxr (requires two bars for directional movement)
- Dmi (requires two bars for directional movement)
- Dmx (requires two bars for directional comparison)
+272
View File
@@ -0,0 +1,272 @@
using System.Runtime.CompilerServices;
namespace QuanTAlib;
/// <summary>
/// GRANGER: Granger Causality Test
/// A statistical test to determine whether one time series is useful in forecasting another.
/// Tests if past values of X help predict future values of Y beyond Y's own past values.
/// Returns a value between 0 and 1 representing the probability that X does not Granger-cause Y.
/// </summary>
/// <remarks>
/// The Granger Causality calculation process:
/// 1. Fits two regression models:
/// - Restricted model: Y(t) = α₀ + Σ(β₁ᵢY(t-i)) + ε(t)
/// - Unrestricted model: Y(t) = α₀ + Σ(β₁ᵢY(t-i)) + Σ(β₂ᵢX(t-i)) + ε(t)
/// 2. Calculates F-statistic comparing the models
/// 3. Computes p-value from F-distribution
///
/// Key characteristics:
/// - Tests predictive causality, not true causation
/// - Sensitive to lag selection
/// - Assumes stationarity of time series
/// - Useful for lead/lag relationship analysis
///
/// Formula:
/// F = ((RSS₁ - RSS₂)/p) / (RSS₂/(n-2p-1))
/// where:
/// RSS₁ = residual sum of squares from restricted model
/// RSS₂ = residual sum of squares from unrestricted model
/// p = number of lags
/// n = number of observations
///
/// Market Applications:
/// - Lead/lag analysis between markets
/// - Price discovery analysis
/// - Market efficiency testing
/// - Intermarket analysis
/// - Risk spillover detection
///
/// Sources:
/// https://en.wikipedia.org/wiki/Granger_causality
/// "Investigating Causal Relations by Econometric Models and Cross-spectral Methods" - C.W.J. Granger
///
/// Note: Assumes linear relationships and stationarity
/// </remarks>
[SkipLocalsInit]
public sealed class Granger : AbstractBase
{
private readonly int Lags;
private readonly CircularBuffer _xValues;
private readonly CircularBuffer _yValues;
private const double Epsilon = 1e-10;
private const int MinimumLags = 1;
/// <param name="lags">The number of lags to use in the Granger causality test.</param>
/// <exception cref="ArgumentOutOfRangeException">Thrown when lags is less than 1.</exception>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Granger(int lags)
{
if (lags < MinimumLags)
{
throw new ArgumentOutOfRangeException(nameof(lags),
"Number of lags must be at least 1 for Granger causality test.");
}
Lags = lags;
WarmupPeriod = lags + 1;
_xValues = new CircularBuffer(lags * 2); // Need extra space for lagged values
_yValues = new CircularBuffer(lags * 2);
Name = $"Granger(lags={lags})";
Init();
}
/// <param name="source">The data source object that publishes updates.</param>
/// <param name="lags">The number of lags to use in the Granger causality test.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Granger(object source, int lags) : this(lags)
{
var pubEvent = source.GetType().GetEvent("Pub");
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override void Init()
{
base.Init();
_xValues.Clear();
_yValues.Clear();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected override void ManageState(bool isNew)
{
if (isNew)
{
_lastValidValue = Input.Value;
_index++;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private double CalculateRSS(ReadOnlySpan<double> y, ReadOnlySpan<double> yhat)
{
double rss = 0;
for (int i = 0; i < y.Length; i++)
{
double residual = y[i] - yhat[i];
rss += residual * residual;
}
return rss;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static void FitOLS(ReadOnlySpan<double> y, ReadOnlySpan<double> x, Span<double> beta)
{
// Simple OLS implementation for y = Xβ + ε
int n = y.Length;
int k = beta.Length;
// Create X matrix (including constant term)
var X = new double[n, k];
for (int i = 0; i < n; i++)
{
X[i, 0] = 1.0; // Constant term
for (int j = 1; j < k; j++)
{
X[i, j] = x[i * (k - 1) + (j - 1)];
}
}
// Calculate β = (X'X)⁻¹X'y
var XtX = new double[k, k];
var Xty = new double[k];
// Calculate X'X and X'y
for (int i = 0; i < k; i++)
{
for (int j = 0; j < k; j++)
{
double sum = 0;
for (int l = 0; l < n; l++)
{
sum += X[l, i] * X[l, j];
}
XtX[i, j] = sum;
}
double sum2 = 0;
for (int l = 0; l < n; l++)
{
sum2 += X[l, i] * y[l];
}
Xty[i] = sum2;
}
// Solve system of equations
for (int i = 0; i < k; i++)
{
double pivot = XtX[i, i];
if (Math.Abs(pivot) > Epsilon)
{
for (int j = 0; j < k; j++)
{
XtX[i, j] /= pivot;
}
Xty[i] /= pivot;
for (int j = 0; j < k; j++)
{
if (i != j)
{
double factor = XtX[j, i];
for (int l = 0; l < k; l++)
{
XtX[j, l] -= factor * XtX[i, l];
}
Xty[j] -= factor * Xty[i];
}
}
}
}
// Copy results to beta
for (int i = 0; i < k; i++)
{
beta[i] = Xty[i];
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private double CalculateFStatistic(double rss1, double rss2, int n, int p)
{
// Calculate F-statistic
double numerator = (rss1 - rss2) / p;
double denominator = rss2 / (n - 2 * p - 1);
return numerator / denominator;
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
private static double FDistributionPValue(double f, int df1, int df2)
{
// Approximate p-value from F-distribution
// Using a simplified approximation for performance
double v = df2 / (df2 + df1 * f);
return Math.Pow(v, df2 / 2.0);
}
[MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
protected override double Calculation()
{
ManageState(Input.IsNew);
_xValues.Add(Input.Value, Input.IsNew);
_yValues.Add(Input2.Value, Input.IsNew);
double pValue = 1.0; // Null hypothesis: X does not Granger-cause Y
if (_xValues.Count >= WarmupPeriod && _yValues.Count >= WarmupPeriod)
{
int n = _xValues.Count - Lags;
if (n > 2 * Lags + 1)
{
ReadOnlySpan<double> x = _xValues.GetSpan();
ReadOnlySpan<double> y = _yValues.GetSpan();
// Prepare data for regression
var yData = y.Slice(Lags, n).ToArray();
var restricted = new double[Lags + 1];
var unrestricted = new double[2 * Lags + 1];
// Fit restricted model (only Y lags)
FitOLS(yData, y.Slice(0, n), restricted);
// Calculate RSS for restricted model
var yhatRestricted = new double[n];
for (int i = 0; i < n; i++)
{
yhatRestricted[i] = restricted[0];
for (int j = 0; j < Lags; j++)
{
yhatRestricted[i] += restricted[j + 1] * y[i + Lags - j - 1];
}
}
double rss1 = CalculateRSS(yData, yhatRestricted);
// Fit unrestricted model (Y and X lags)
FitOLS(yData, x.Slice(0, n), unrestricted);
// Calculate RSS for unrestricted model
var yhatUnrestricted = new double[n];
for (int i = 0; i < n; i++)
{
yhatUnrestricted[i] = unrestricted[0];
for (int j = 0; j < Lags; j++)
{
yhatUnrestricted[i] += unrestricted[j + 1] * y[i + Lags - j - 1];
yhatUnrestricted[i] += unrestricted[j + Lags + 1] * x[i + Lags - j - 1];
}
}
double rss2 = CalculateRSS(yData, yhatUnrestricted);
// Calculate F-statistic and p-value
if (rss2 > Epsilon)
{
double f = CalculateFStatistic(rss1, rss2, n, Lags);
pValue = FDistributionPValue(f, Lags, n - 2 * Lags - 1);
}
}
}
IsHot = _xValues.Count >= WarmupPeriod && _yValues.Count >= WarmupPeriod;
return pValue;
}
}
+2 -2
View File
@@ -1,11 +1,12 @@
# Statistics indicators
Done: 21, Todo: 2
Done: 22, Todo: 1
✔️ BETA - Beta coefficient measuring volatility relative to market
✔️ CORR - Correlation coefficient between two series
✔️ COVAR - Covariance between two series
✔️ CURVATURE - Curvature of a time series
✔️ ENTROPY - Information entropy of a series
✔️ GRANGER - Granger causality test
✔️ HURST - Hurst exponent for trend strength
✔️ KENDALL - Kendall rank correlation
✔️ KURTOSIS - Kurtosis measuring tail extremity
@@ -23,4 +24,3 @@ Done: 21, Todo: 2
✔️ VARIANCE - Statistical variance
✔️ ZSCORE - Z-score standardization
COINTEGRATION - Test for cointegrated series
GRANGER - Granger causality test