mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-30 02:27:43 +00:00
prep
This commit is contained in:
@@ -20,8 +20,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Momentum", "quantower\Momen
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Experiments", "quantower\Experiments\_Experiments.csproj", "{F7F1F8D3-DAC0-4E9F-1FB2-F88D5F0E0E04}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntheticVendor", "SyntheticVendor\SyntheticVendor.csproj", "{1CF111D9-33E6-4A11-8FEC-F23300A78D15}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{2D97C971-20BF-40DB-94AA-3279F787D3CB}"
|
||||
EndProject
|
||||
Global
|
||||
@@ -65,10 +63,6 @@ Global
|
||||
{F7F1F8D3-DAC0-4E9F-1FB2-F88D5F0E0E04}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F7F1F8D3-DAC0-4E9F-1FB2-F88D5F0E0E04}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F7F1F8D3-DAC0-4E9F-1FB2-F88D5F0E0E04}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{1CF111D9-33E6-4A11-8FEC-F23300A78D15}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2D97C971-20BF-40DB-94AA-3279F787D3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2D97C971-20BF-40DB-94AA-3279F787D3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2D97C971-20BF-40DB-94AA-3279F787D3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
||||
+31
-58
@@ -10,101 +10,74 @@ public class EventingTests
|
||||
private const int DefaultPeriod = 10;
|
||||
private const double Tolerance = 1e-9;
|
||||
|
||||
private static readonly (string Name, object[] DirectParams, object[] EventParams)[] ValueIndicators = new[]
|
||||
private static readonly (string Name, object[] DirectParams, object[] EventParams)[] ValueIndicators =
|
||||
{
|
||||
("Afirma", new object[] { DefaultPeriod, DefaultPeriod, Afirma.WindowType.BlackmanHarris }, new object[] { new TSeries(), DefaultPeriod, DefaultPeriod, Afirma.WindowType.BlackmanHarris }),
|
||||
("Alma", new object[] { DefaultPeriod, 0.85, 6.0 }, new object[] { new TSeries(), DefaultPeriod, 0.85, 6.0 }),
|
||||
("Beta", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Convolution", new object[] { new double[] {1,2,3,2,1} }, new object[] { new TSeries(), new double[] {1,2,3,2,1} }),
|
||||
("Corr", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Covar", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Curvature", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Dema", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Dsma", new object[] { DefaultPeriod, 0.9 }, new object[] { new TSeries(), DefaultPeriod, 0.9 }),
|
||||
("Dwma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Ema", new object[] { DefaultPeriod, true }, new object[] { new TSeries(), DefaultPeriod, true }),
|
||||
("Entropy", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Epma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Pwma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Fisher", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Frama", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Fwma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Gma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Granger", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Hma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Htit", System.Array.Empty<object>(), new object[] { new TSeries() }),
|
||||
("Htit", Array.Empty<object>(), new object[] { new TSeries() }),
|
||||
("Hwma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Jma", new object[] { DefaultPeriod, 0, 0.45, 10 }, new object[] { new TSeries(), DefaultPeriod, 0, 0.45, 10 }),
|
||||
("Kama", new object[] { DefaultPeriod, 2, 30 }, new object[] { new TSeries(), DefaultPeriod, 2, 30 }),
|
||||
("Kendall", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Kurtosis", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Ltma", new object[] { 0.2 }, new object[] { new TSeries(), 0.2 }),
|
||||
("Maaf", new object[] { 39, 0.002 }, new object[] { new TSeries(), 39, 0.002 }),
|
||||
("Mama", new object[] { 0.5, 0.05 }, new object[] { new TSeries(), 0.5, 0.05 }),
|
||||
("Max", new object[] { DefaultPeriod, 0.0 }, new object[] { new TSeries(), DefaultPeriod, 0.0 }),
|
||||
("Median", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mgdi", new object[] { DefaultPeriod, 0.6 }, new object[] { new TSeries(), DefaultPeriod, 0.6 }),
|
||||
("Min", new object[] { DefaultPeriod, 0.0 }, new object[] { new TSeries(), DefaultPeriod, 0.0 }),
|
||||
("Mma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mode", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Percentile", new object[] { DefaultPeriod, 0.5 }, new object[] { new TSeries(), DefaultPeriod, 0.5 }),
|
||||
("Pwma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Qema", new object[] { 0.2, 0.2, 0.2, 0.2 }, new object[] { new TSeries(), 0.2, 0.2, 0.2, 0.2 }),
|
||||
("Rema", new object[] { DefaultPeriod, 0.5 }, new object[] { new TSeries(), DefaultPeriod, 0.5 }),
|
||||
("Rma", new object[] { DefaultPeriod, true }, new object[] { new TSeries(), DefaultPeriod, true }),
|
||||
("Sma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Wma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Tema", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Zlema", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Sinema", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Smma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("T3", new object[] { DefaultPeriod, 0.7, true }, new object[] { new TSeries(), DefaultPeriod, 0.7, true }),
|
||||
("Trima", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Vidya", new object[] { DefaultPeriod, 0, 0.2 }, new object[] { new TSeries(), DefaultPeriod, 0, 0.2 }),
|
||||
("Apo", new object[] { 12, 26 }, new object[] { new TSeries(), 12, 26 }),
|
||||
("Macd", new object[] { 12, 26, 9 }, new object[] { new TSeries(), 12, 26, 9 }),
|
||||
("Rsi", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Rsx", new object[] { DefaultPeriod, 0, 0.55 }, new object[] { new TSeries(), DefaultPeriod, 0, 0.55 }),
|
||||
("Cmo", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Cog", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Curvature", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Entropy", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Kurtosis", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Max", new object[] { DefaultPeriod, 0.0 }, new object[] { new TSeries(), DefaultPeriod, 0.0 }),
|
||||
("Median", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Min", new object[] { DefaultPeriod, 0.0 }, new object[] { new TSeries(), DefaultPeriod, 0.0 }),
|
||||
("Mode", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Percentile", new object[] { DefaultPeriod, 0.5 }, new object[] { new TSeries(), DefaultPeriod, 0.5 }),
|
||||
("Skew", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Slope", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Stddev", new object[] { DefaultPeriod, false }, new object[] { new TSeries(), DefaultPeriod, false }),
|
||||
("Variance", new object[] { DefaultPeriod, false }, new object[] { new TSeries(), DefaultPeriod, false }),
|
||||
("Zscore", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Beta", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Corr", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Covar", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Kendall", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Sma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Smma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Spearman", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Hv", new object[] { DefaultPeriod, false }, new object[] { new TSeries(), DefaultPeriod, false }),
|
||||
("Jvolty", new object[] { DefaultPeriod, 0 }, new object[] { new TSeries(), DefaultPeriod, 0 }),
|
||||
("Rv", new object[] { DefaultPeriod, false }, new object[] { new TSeries(), DefaultPeriod, false }),
|
||||
("Rvi", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mae", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mapd", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mape", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mase", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mda", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Me", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mpe", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Mse", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Msle", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Rae", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Rmse", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Rmsle", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Rse", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Smape", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Rsquared", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Huber", new object[] { DefaultPeriod, 1.0 }, new object[] { new TSeries(), DefaultPeriod, 1.0 }),
|
||||
("Cti", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod })
|
||||
("Stddev", new object[] { DefaultPeriod, false }, new object[] { new TSeries(), DefaultPeriod, false }),
|
||||
("T3", new object[] { DefaultPeriod, 0.7, true }, new object[] { new TSeries(), DefaultPeriod, 0.7, true }),
|
||||
("Tema", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Trima", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Variance", new object[] { DefaultPeriod, false }, new object[] { new TSeries(), DefaultPeriod, false }),
|
||||
("Vidya", new object[] { DefaultPeriod, 0, 0.2 }, new object[] { new TSeries(), DefaultPeriod, 0, 0.2 }),
|
||||
("Wma", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Zlema", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod }),
|
||||
("Zscore", new object[] { DefaultPeriod }, new object[] { new TSeries(), DefaultPeriod })
|
||||
};
|
||||
|
||||
private static readonly (string Name, object[] DirectParams, object[] EventParams)[] BarIndicators = new[]
|
||||
private static readonly (string Name, object[] DirectParams, object[] EventParams)[] BarIndicators =
|
||||
{
|
||||
("Adl", System.Array.Empty<object>(), new object[] { new TBarSeries() }),
|
||||
("Adl", Array.Empty<object>(), new object[] { new TBarSeries() }),
|
||||
("Adosc", new object[] { 3, 10 }, new object[] { new TBarSeries(), 3, 10 }),
|
||||
("Aobv", System.Array.Empty<object>(), new object[] { new TBarSeries() }),
|
||||
("Aobv", Array.Empty<object>(), new object[] { new TBarSeries() }),
|
||||
("Cmf", new object[] { 20 }, new object[] { new TBarSeries(), 20 }),
|
||||
("Eom", new object[] { 14 }, new object[] { new TBarSeries(), 14 }),
|
||||
("Kvo", new object[] { 34, 55 }, new object[] { new TBarSeries(), 34, 55 }),
|
||||
("Atr", new object[] { 14 }, new object[] { new TBarSeries(), 14 }),
|
||||
("Chop", new object[] { 14 }, new object[] { new TBarSeries(), 14 }),
|
||||
("Dosc", System.Array.Empty<object>(), new object[] { new TBarSeries() })
|
||||
("Dosc", Array.Empty<object>(), new object[] { new TBarSeries() })
|
||||
};
|
||||
|
||||
public static IEnumerable<object[]> GetValueIndicatorData()
|
||||
|
||||
@@ -39,6 +39,13 @@ public class StatisticsUpdateTests : UpdateTestBase
|
||||
TestTValueUpdate(indicator, indicator.Calc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Granger_Update()
|
||||
{
|
||||
var indicator = new Granger(lags: 5);
|
||||
TestDualTValueUpdate(indicator, indicator.Calc);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Hurst_Update()
|
||||
{
|
||||
|
||||
+4
-4
@@ -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
|
||||
|
||||
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
#!csharp
|
||||
|
||||
#r "..\lib\obj\Debug\QuanTAlib.dll"
|
||||
#r "../lib/obj/Debug/QuanTAlib.dll"
|
||||
using QuanTAlib;
|
||||
QuanTAlib.Formatters.Initialize();
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
#!meta
|
||||
|
||||
{"kernelInfo":{"defaultKernelName":"csharp","items":[{"aliases":[],"name":"csharp"}]}}
|
||||
|
||||
#!csharp
|
||||
|
||||
#r "../lib/obj/Debug/QuanTAlib.dll"
|
||||
using QuanTAlib;
|
||||
QuanTAlib.Formatters.Initialize();
|
||||
|
||||
#!csharp
|
||||
|
||||
#r "nuget: ScottPlot"
|
||||
|
||||
using ScottPlot;
|
||||
using Microsoft.DotNet.Interactive.Formatting;
|
||||
Formatter.Register(typeof(ScottPlot.Plot), (p, w) =>
|
||||
w.Write(((ScottPlot.Plot)p).GetSvgXml(600, 300)), HtmlFormatter.MimeType);
|
||||
|
||||
#!csharp
|
||||
|
||||
GbmFeed feed = new();
|
||||
TSeries data = new(feed.Close);
|
||||
Ccv ma = new(feed,5);
|
||||
TSeries result = new(ma);
|
||||
feed.Add(12);
|
||||
display(result);
|
||||
Reference in New Issue
Block a user