mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-01 03:07:43 +00:00
feat: add 8 new indicators with full integration
New indicators: - HWC (Holt-Winters Channel) — channels, 27 tests - VWMACD (Volume-Weighted MACD) — momentum, 38 tests - Squeeze Pro — oscillators, 69 tests - BW_MFI (Bill Williams MFI) — oscillators - DSTOCH (Double Stochastic) — oscillators - ATRSTOP (ATR Trailing Stop) — reversals - VSTOP (Volatility Stop) — reversals - Convexity (Beta Convexity) — statistics, 23 tests Integration: - Python bridge: Exports.cs, _bridge.py, wrapper modules - Documentation: _sidebar.md, _index.md pages, SPEC.md - All analyzer warnings fixed (MA0074, xUnit2013, S2699) Build: 0 warnings, 0 errors | Tests: 15,933 passed, 0 failed
This commit is contained in:
@@ -308,6 +308,20 @@ public static unsafe partial class Exports
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_atrstop")]
|
||||
public static int QtlAtrstop(double* high, double* low, double* close, double* output, int n, int period, double multiplier)
|
||||
{
|
||||
if (high == null || low == null || close == null || output == null) return StatusCodes.QTL_ERR_NULL_PTR;
|
||||
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
|
||||
if (period <= 0) return StatusCodes.QTL_ERR_INVALID_PARAM;
|
||||
try
|
||||
{
|
||||
Atrstop.Batch(Src(high, n), Src(low, n), Src(close, n), Dst(output, n), period, multiplier);
|
||||
return StatusCodes.QTL_OK;
|
||||
}
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_atr")]
|
||||
public static int QtlAtr(double* sourceOpen, double* sourceHigh, double* sourceLow, double* sourceClose, double* sourceVolume, int period, int n, double* dst)
|
||||
{
|
||||
@@ -372,6 +386,44 @@ public static unsafe partial class Exports
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_bwmfi")]
|
||||
public static int QtlBwMfi(double* high, double* low, double* volume, double* mfiOutput, double* zoneOutput, int n)
|
||||
{
|
||||
if (high == null || low == null || volume == null || mfiOutput == null || zoneOutput == null) return StatusCodes.QTL_ERR_NULL_PTR;
|
||||
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
|
||||
try
|
||||
{
|
||||
var hi = Src(high, n);
|
||||
var lo = Src(low, n);
|
||||
var vol = Src(volume, n);
|
||||
var mfiTmp = new double[n];
|
||||
var zoneTmp = new int[n];
|
||||
BwMfi.Batch(hi, lo, vol, mfiTmp.AsSpan(), zoneTmp.AsSpan());
|
||||
mfiTmp.AsSpan().CopyTo(Dst(mfiOutput, n));
|
||||
var zoneDst = Dst(zoneOutput, n);
|
||||
for (int i = 0; i < n; i++)
|
||||
{
|
||||
zoneDst[i] = zoneTmp[i];
|
||||
}
|
||||
return StatusCodes.QTL_OK;
|
||||
}
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_dstoch")]
|
||||
public static int QtlDstoch(double* high, double* low, double* close, double* output, int n, int period)
|
||||
{
|
||||
if (high == null || low == null || close == null || output == null) return StatusCodes.QTL_ERR_NULL_PTR;
|
||||
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
|
||||
if (period <= 0) return StatusCodes.QTL_ERR_INVALID_PARAM;
|
||||
try
|
||||
{
|
||||
Dstoch.Batch(Src(high, n), Src(low, n), Src(close, n), Dst(output, n), period);
|
||||
return StatusCodes.QTL_OK;
|
||||
}
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_cci")]
|
||||
public static int QtlCci(double* sourceOpen, double* sourceHigh, double* sourceLow, double* sourceClose, double* sourceVolume, int period, int n, double* dst)
|
||||
{
|
||||
@@ -2848,6 +2900,19 @@ public static unsafe partial class Exports
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_squeeze_pro")]
|
||||
public static int QtlSqueezePro(double* high, double* low, double* close, double* momOut, double* sqOut, int n, int period, double bbMult, double kcMultWide, double kcMultNormal, double kcMultNarrow, int momLength, int momSmooth, int useSma)
|
||||
{
|
||||
if (high == null || low == null || close == null || momOut == null || sqOut == null) return StatusCodes.QTL_ERR_NULL_PTR;
|
||||
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
|
||||
try
|
||||
{
|
||||
SqueezePro.Batch(Src(high, n), Src(low, n), Src(close, n), Dst(momOut, n), Dst(sqOut, n), period, bbMult, kcMultWide, kcMultNormal, kcMultNarrow, momLength, momSmooth, useSma != 0);
|
||||
return StatusCodes.QTL_OK;
|
||||
}
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_ssf2")]
|
||||
public static int QtlSsf2(double* source, double* output, int n, int period)
|
||||
{
|
||||
@@ -3385,6 +3450,20 @@ public static unsafe partial class Exports
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_vstop")]
|
||||
public static int QtlVstop(double* high, double* low, double* close, double* output, int n, int period, double multiplier)
|
||||
{
|
||||
if (high == null || low == null || close == null || output == null) return StatusCodes.QTL_ERR_NULL_PTR;
|
||||
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
|
||||
if (period <= 0) return StatusCodes.QTL_ERR_INVALID_PARAM;
|
||||
try
|
||||
{
|
||||
Vstop.Batch(Src(high, n), Src(low, n), Src(close, n), Dst(output, n), period, multiplier);
|
||||
return StatusCodes.QTL_OK;
|
||||
}
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_vov")]
|
||||
public static int QtlVov(double* source, double* output, int n, int volatilityPeriod, int vovPeriod)
|
||||
{
|
||||
|
||||
@@ -242,6 +242,27 @@ public static unsafe partial class Exports
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
// Vwmacd: multi-output (close, volume → vwmacd, signal, histogram)
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_vwmacd")]
|
||||
public static int QtlVwmacd(double* close, double* volume, int n,
|
||||
double* dstVwmacd, double* dstSignal, double* dstHist,
|
||||
int fastPeriod, int slowPeriod, int signalPeriod)
|
||||
{
|
||||
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
|
||||
if (close == null || volume == null ||
|
||||
dstVwmacd == null || dstSignal == null || dstHist == null) return StatusCodes.QTL_ERR_NULL_PTR;
|
||||
if (fastPeriod < 1 || slowPeriod < 1 || signalPeriod < 1) return StatusCodes.QTL_ERR_INVALID_PARAM;
|
||||
try
|
||||
{
|
||||
Vwmacd.Batch(
|
||||
Src(close, n), Src(volume, n),
|
||||
Dst(dstVwmacd, n), Dst(dstSignal, n), Dst(dstHist, n),
|
||||
fastPeriod, slowPeriod, signalPeriod);
|
||||
return StatusCodes.QTL_OK;
|
||||
}
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// §8.3 Oscillators
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
@@ -841,6 +862,26 @@ public static unsafe partial class Exports
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
// Hwc: multi-output (src → upper, middle, lower; int period, double multiplier)
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_hwc")]
|
||||
public static int QtlHwc(double* src, int n,
|
||||
double* dstUpper, double* dstMiddle, double* dstLower,
|
||||
int period, double multiplier)
|
||||
{
|
||||
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
|
||||
if (src == null || dstUpper == null || dstMiddle == null || dstLower == null) return StatusCodes.QTL_ERR_NULL_PTR;
|
||||
if (period < 1) return StatusCodes.QTL_ERR_INVALID_PARAM;
|
||||
try
|
||||
{
|
||||
Hwc.Batch(
|
||||
Src(src, n),
|
||||
Dst(dstUpper, n), Dst(dstMiddle, n), Dst(dstLower, n),
|
||||
period, multiplier);
|
||||
return StatusCodes.QTL_OK;
|
||||
}
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// §8.7 Volatility
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
@@ -1179,6 +1220,28 @@ public static unsafe partial class Exports
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
// Convexity: multi-output (asset, market → betaStd, betaUp, betaDown, ratio, convexity)
|
||||
[UnmanagedCallersOnly(EntryPoint = "qtl_convexity")]
|
||||
public static int QtlConvexity(double* asset, double* market, int n,
|
||||
double* dstBetaStd, double* dstBetaUp, double* dstBetaDown,
|
||||
double* dstRatio, double* dstConvexity, int period)
|
||||
{
|
||||
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
|
||||
if (asset == null || market == null ||
|
||||
dstBetaStd == null || dstBetaUp == null || dstBetaDown == null ||
|
||||
dstRatio == null || dstConvexity == null) return StatusCodes.QTL_ERR_NULL_PTR;
|
||||
if (period < 1) return StatusCodes.QTL_ERR_INVALID_PARAM;
|
||||
try
|
||||
{
|
||||
Convexity.Batch(
|
||||
Src(asset, n), Src(market, n),
|
||||
Dst(dstBetaStd, n), Dst(dstBetaUp, n), Dst(dstBetaDown, n),
|
||||
Dst(dstRatio, n), Dst(dstConvexity, n), period);
|
||||
return StatusCodes.QTL_OK;
|
||||
}
|
||||
catch { return StatusCodes.QTL_ERR_INTERNAL; }
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
// §8.10 Error Metrics
|
||||
// ═══════════════════════════════════════════════════════════════════════
|
||||
|
||||
Reference in New Issue
Block a user