mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-28 17:57:45 +00:00
305 lines
18 KiB
Python
305 lines
18 KiB
Python
"""Low-level ctypes bindings for every quantalib NativeAOT export.
|
|
|
|
Each native function is bound via ``_bind`` at module load. If the shared
|
|
library was compiled without a particular export the binding is silently
|
|
skipped (the corresponding ``HAS_*`` flag stays False).
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import ctypes
|
|
from ctypes import c_double, c_int, POINTER
|
|
from typing import Final
|
|
|
|
from ._loader import load_native_library
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Status codes (mirror StatusCodes.cs)
|
|
# ---------------------------------------------------------------------------
|
|
QTL_OK: Final[int] = 0
|
|
QTL_ERR_NULL_PTR: Final[int] = 1
|
|
QTL_ERR_INVALID_LENGTH: Final[int] = 2
|
|
QTL_ERR_INVALID_PARAM: Final[int] = 3
|
|
QTL_ERR_INTERNAL: Final[int] = 4
|
|
|
|
|
|
class QtlError(Exception):
|
|
"""Base exception for quantalib native errors."""
|
|
|
|
|
|
class QtlNullPointerError(QtlError):
|
|
pass
|
|
|
|
|
|
class QtlInvalidLengthError(QtlError):
|
|
pass
|
|
|
|
|
|
class QtlInvalidParamError(QtlError):
|
|
pass
|
|
|
|
|
|
class QtlInternalError(QtlError):
|
|
pass
|
|
|
|
|
|
_STATUS_MAP: dict[int, type[QtlError]] = {
|
|
QTL_ERR_NULL_PTR: QtlNullPointerError,
|
|
QTL_ERR_INVALID_LENGTH: QtlInvalidLengthError,
|
|
QTL_ERR_INVALID_PARAM: QtlInvalidParamError,
|
|
QTL_ERR_INTERNAL: QtlInternalError,
|
|
}
|
|
|
|
|
|
def _check(status: int) -> None:
|
|
"""Raise if *status* is not QTL_OK."""
|
|
if status == QTL_OK:
|
|
return
|
|
exc_type = _STATUS_MAP.get(status, QtlError)
|
|
raise exc_type(f"quantalib native call failed (status={status})")
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Load native library
|
|
# ---------------------------------------------------------------------------
|
|
_lib = load_native_library()
|
|
|
|
# Shorthand type aliases
|
|
_dp = POINTER(c_double) # double*
|
|
_ip = POINTER(c_int) # int*
|
|
_ci = c_int
|
|
_cd = c_double
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# ABI signature pattern templates
|
|
#
|
|
# Pattern A : (src*, n, dst*, period) → single-input + int
|
|
# Pattern A2: (src*, n, dst*, alpha) → single-input + double
|
|
# Pattern A3: (src*, n, dst*) → single-input no params
|
|
# Pattern B : (h*, l*, c*, v*, n, dst*, period) → HLCV + int
|
|
# Pattern C : (o*, h*, l*, c*, n, dst*) → OHLC no extra
|
|
# Pattern C2: (o*, h*, l*, c*, n, dst*, double) → OHLC + double
|
|
# Pattern D : (h*, l*, n, dst*) → HL
|
|
# Pattern E : (h*, l*, c*, n, dst*) → HLC
|
|
# Pattern F : (actual*, predicted*, n, dst*, period) → dual-input + int
|
|
# Pattern G : (src*, vol*, n, dst*) → source+volume
|
|
# Pattern G2: (src*, vol*, n, dst*, period) → source+volume+int
|
|
# Pattern H : (x*, y*, n, dst*, period) → X+Y + int
|
|
# Pattern I : multi-output (various)
|
|
# ---------------------------------------------------------------------------
|
|
|
|
# Common argtypes per pattern
|
|
_PA = [_dp, _ci, _dp, _ci] # Pattern A
|
|
_PA2 = [_dp, _ci, _dp, _cd] # Pattern A (alpha)
|
|
_PA3 = [_dp, _ci, _dp] # Pattern A (no param)
|
|
_PB = [_dp, _dp, _dp, _dp, _ci, _dp, _ci] # Pattern B (HLCV)
|
|
_PC = [_dp, _dp, _dp, _dp, _ci, _dp] # Pattern C (OHLC)
|
|
_PC2 = [_dp, _dp, _dp, _dp, _ci, _dp, _cd] # Pattern C (OHLC+double)
|
|
_PD = [_dp, _dp, _ci, _dp] # Pattern D (HL)
|
|
_PE = [_dp, _dp, _dp, _ci, _dp] # Pattern E (HLC)
|
|
_PF = [_dp, _dp, _ci, _dp, _ci] # Pattern F
|
|
_PG = [_dp, _dp, _ci, _dp] # Pattern G
|
|
_PG2 = [_dp, _dp, _ci, _dp, _ci] # Pattern G2
|
|
_PH = [_dp, _dp, _ci, _dp, _ci] # Pattern H
|
|
|
|
|
|
def _bind(name: str, argtypes: list[object]) -> bool:
|
|
"""Bind a single native function. Returns True if found."""
|
|
fn = getattr(_lib, name, None)
|
|
if fn is None:
|
|
return False
|
|
fn.argtypes = argtypes
|
|
fn.restype = _ci
|
|
return True
|
|
|
|
|
|
# ---------------------------------------------------------------------------
|
|
# Health check
|
|
# ---------------------------------------------------------------------------
|
|
HAS_SKELETON = _bind("qtl_skeleton_noop", [_dp, _ci, _dp])
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.1 Core
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_AVGPRICE = _bind("qtl_avgprice", _PC)
|
|
HAS_MEDPRICE = _bind("qtl_medprice", _PD)
|
|
HAS_TYPPRICE = _bind("qtl_typprice", [_dp, _dp, _dp, _ci, _dp]) # OHL (no close!)
|
|
HAS_MIDBODY = _bind("qtl_midbody", [_dp, _dp, _ci, _dp]) # OC
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.2 Momentum
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_RSI = _bind("qtl_rsi", _PA)
|
|
HAS_ROC = _bind("qtl_roc", _PA)
|
|
HAS_MOM = _bind("qtl_mom", _PA)
|
|
HAS_CMO = _bind("qtl_cmo", _PA)
|
|
HAS_TSI = _bind("qtl_tsi", [_dp, _ci, _dp, _ci, _ci]) # longP, shortP
|
|
HAS_APO = _bind("qtl_apo", [_dp, _ci, _dp, _ci, _ci]) # fast, slow
|
|
HAS_BIAS = _bind("qtl_bias", _PA)
|
|
HAS_CFO = _bind("qtl_cfo", _PA)
|
|
HAS_CFB = _bind("qtl_cfb", [_dp, _ci, _dp, _ip, _ci]) # special
|
|
HAS_ASI = _bind("qtl_asi", _PC2) # OHLC + double limit
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.3 Oscillators
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_FISHER = _bind("qtl_fisher", _PA)
|
|
HAS_FISHER04 = _bind("qtl_fisher04", _PA)
|
|
HAS_DPO = _bind("qtl_dpo", _PA)
|
|
HAS_TRIX = _bind("qtl_trix", _PA)
|
|
HAS_INERTIA = _bind("qtl_inertia", _PA)
|
|
HAS_RSX = _bind("qtl_rsx", _PA)
|
|
HAS_ER = _bind("qtl_er", _PA)
|
|
HAS_CTI = _bind("qtl_cti", _PA)
|
|
HAS_REFLEX = _bind("qtl_reflex", _PA)
|
|
HAS_TRENDFLEX = _bind("qtl_trendflex", _PA)
|
|
HAS_KRI = _bind("qtl_kri", _PA)
|
|
HAS_PSL = _bind("qtl_psl", _PA)
|
|
HAS_DECO = _bind("qtl_deco", [_dp, _ci, _dp, _ci, _ci]) # shortP, longP
|
|
HAS_DOSC = _bind("qtl_dosc", [_dp, _ci, _dp, _ci, _ci, _ci, _ci]) # rsiP, ema1P, ema2P, sigP
|
|
HAS_DYMOI = _bind("qtl_dymoi", [_dp, _ci, _dp, _ci, _ci, _ci, _ci, _ci]) # p1..p5
|
|
HAS_CRSI = _bind("qtl_crsi", [_dp, _ci, _dp, _ci, _ci, _ci]) # rsiP, streakP, rankP
|
|
HAS_BBB = _bind("qtl_bbb", [_dp, _ci, _dp, _ci, _cd]) # period, mult
|
|
HAS_BBI = _bind("qtl_bbi", [_dp, _ci, _dp, _ci, _ci, _ci, _ci]) # p1..p4
|
|
HAS_DEM = _bind("qtl_dem", [_dp, _dp, _ci, _dp, _ci]) # high,low,n,dst,period
|
|
HAS_BRAR = _bind("qtl_brar", [_dp, _dp, _dp, _dp, _ci, _dp, _dp, _ci]) # OHLC + 2 outputs + period
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.4 Trends — FIR
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_SMA = _bind("qtl_sma", _PA)
|
|
HAS_WMA = _bind("qtl_wma", _PA)
|
|
HAS_HMA = _bind("qtl_hma", _PA)
|
|
HAS_TRIMA = _bind("qtl_trima", _PA)
|
|
HAS_SWMA = _bind("qtl_swma", _PA)
|
|
HAS_DWMA = _bind("qtl_dwma", _PA)
|
|
HAS_BLMA = _bind("qtl_blma", _PA)
|
|
HAS_ALMA = _bind("qtl_alma", [_dp, _ci, _dp, _ci, _cd, _cd]) # period, offset, sigma
|
|
HAS_LSMA = _bind("qtl_lsma", _PA)
|
|
HAS_SGMA = _bind("qtl_sgma", _PA)
|
|
HAS_SINEMA = _bind("qtl_sinema", _PA)
|
|
HAS_HANMA = _bind("qtl_hanma", _PA)
|
|
HAS_PARZEN = _bind("qtl_parzen", _PA)
|
|
HAS_TSF = _bind("qtl_tsf", _PA)
|
|
HAS_CONV = _bind("qtl_conv", [_dp, _ci, _dp, _dp, _ci]) # src,n,dst,kernel*,kernelLen
|
|
HAS_BWMA = _bind("qtl_bwma", [_dp, _ci, _dp, _ci, _ci]) # period, polyOrder
|
|
HAS_CRMA = _bind("qtl_crma", [_dp, _ci, _dp, _ci, _cd]) # period, volumeFactor
|
|
HAS_SP15 = _bind("qtl_sp15", _PA)
|
|
HAS_TUKEY_W = _bind("qtl_tukey_w", _PA)
|
|
HAS_RAIN = _bind("qtl_rain", _PA)
|
|
HAS_AFIRMA = _bind("qtl_afirma", [_dp, _ci, _dp, _ci, _ci, _ci]) # src,n,dst,period,windowType,useSimd
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.5 Trends — IIR
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_EMA = _bind("qtl_ema", _PA)
|
|
HAS_EMA_ALPHA = _bind("qtl_ema_alpha", _PA2)
|
|
HAS_DEMA = _bind("qtl_dema", _PA)
|
|
HAS_DEMA_ALPHA = _bind("qtl_dema_alpha", _PA2)
|
|
HAS_TEMA = _bind("qtl_tema", _PA)
|
|
HAS_LEMA = _bind("qtl_lema", _PA)
|
|
HAS_HEMA = _bind("qtl_hema", _PA)
|
|
HAS_AHRENS = _bind("qtl_ahrens", _PA)
|
|
HAS_DECYCLER = _bind("qtl_decycler", _PA)
|
|
HAS_DSMA = _bind("qtl_dsma", [_dp, _ci, _dp, _ci, _cd]) # period, factor
|
|
HAS_GDEMA = _bind("qtl_gdema", [_dp, _ci, _dp, _ci, _cd]) # period, factor
|
|
HAS_CORAL = _bind("qtl_coral", [_dp, _ci, _dp, _ci, _cd]) # period, friction
|
|
HAS_AGC = _bind("qtl_agc", _PA2) # alpha
|
|
HAS_CCYC = _bind("qtl_ccyc", _PA2) # alpha
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.6 Channels
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_BBANDS = _bind("qtl_bbands", [_dp, _ci, _dp, _dp, _dp, _ci, _cd]) # src,n, upper,mid,lower, period,mult
|
|
HAS_ABBER = _bind("qtl_abber", [_dp, _dp, _dp, _dp, _ci, _ci, _cd]) # src,mid,upper,lower,n,period,mult
|
|
HAS_ATRBANDS = _bind("qtl_atrbands", [_dp, _dp, _dp, _ci, _dp, _dp, _dp, _ci, _cd]) # h,l,c,n, upper,mid,lower, period,mult
|
|
HAS_APCHANNEL = _bind("qtl_apchannel", [_dp, _dp, _ci, _dp, _dp, _ci]) # h,l,n, upper,lower, period
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.7 Volatility
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_TR = _bind("qtl_tr", _PE) # HLC
|
|
HAS_BBW = _bind("qtl_bbw", _PA)
|
|
HAS_BBWN = _bind("qtl_bbwn", [_dp, _ci, _dp, _ci, _cd, _ci]) # period, mult, lookback
|
|
HAS_BBWP = _bind("qtl_bbwp", [_dp, _ci, _dp, _ci, _cd, _ci]) # period, mult, lookback
|
|
HAS_STDDEV = _bind("qtl_stddev", _PA)
|
|
HAS_VARIANCE = _bind("qtl_variance", _PA)
|
|
HAS_ETHERM = _bind("qtl_etherm", [_dp, _dp, _ci, _dp, _ci]) # high,low,n,dst,period
|
|
HAS_CCV = _bind("qtl_ccv", [_dp, _ci, _dp, _ci, _ci]) # shortP, longP
|
|
HAS_CV = _bind("qtl_cv", [_dp, _ci, _dp, _ci, _cd, _cd]) # period, minVol, maxVol
|
|
HAS_CVI = _bind("qtl_cvi", [_dp, _ci, _dp, _ci, _ci]) # emaPeriod, rocPeriod
|
|
HAS_EWMA = _bind("qtl_ewma", [_dp, _ci, _dp, _ci, _ci, _ci]) # period, isPop, annFactor
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.8 Volume
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_OBV = _bind("qtl_obv", _PG) # close,vol,n,dst
|
|
HAS_PVT = _bind("qtl_pvt", _PG)
|
|
HAS_PVR = _bind("qtl_pvr", _PG)
|
|
HAS_VF = _bind("qtl_vf", _PG)
|
|
HAS_NVI = _bind("qtl_nvi", _PG)
|
|
HAS_PVI = _bind("qtl_pvi", _PG)
|
|
HAS_TVI = _bind("qtl_tvi", _PG2) # close,vol,n,dst,period
|
|
HAS_PVD = _bind("qtl_pvd", _PG2)
|
|
HAS_VWMA = _bind("qtl_vwma", _PG2)
|
|
HAS_EVWMA = _bind("qtl_evwma", _PG2)
|
|
HAS_EFI = _bind("qtl_efi", _PG2)
|
|
HAS_AOBV = _bind("qtl_aobv", [_dp, _dp, _ci, _dp, _dp]) # close,vol,n,obv,signal
|
|
HAS_MFI = _bind("qtl_mfi", _PB) # HLCV + period
|
|
HAS_CMF = _bind("qtl_cmf", _PB)
|
|
HAS_EOM = _bind("qtl_eom", [_dp, _dp, _dp, _ci, _dp, _ci]) # h,l,v,n,dst,period
|
|
HAS_PVO = _bind("qtl_pvo", [_dp, _ci, _dp, _dp, _dp, _ci, _ci, _ci]) # vol,n, pvo,signal,hist, fast,slow,signal_p
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.9 Statistics
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_ZSCORE = _bind("qtl_zscore", _PA)
|
|
HAS_CMA = _bind("qtl_cma", _PA3) # no period
|
|
HAS_ENTROPY = _bind("qtl_entropy", _PA)
|
|
HAS_CORRELATION = _bind("qtl_correlation", _PH)
|
|
HAS_COVARIANCE = _bind("qtl_covariance", [_dp, _dp, _ci, _dp, _ci, _ci]) # x,y,n,dst,period,isSample
|
|
HAS_COINTEGRATION = _bind("qtl_cointegration", _PH)
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.10 Errors
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_MSE = _bind("qtl_mse", _PF)
|
|
HAS_RMSE = _bind("qtl_rmse", _PF)
|
|
HAS_MAE = _bind("qtl_mae", _PF)
|
|
HAS_MAPE = _bind("qtl_mape", _PF)
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.11 Filters
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_BESSEL = _bind("qtl_bessel", _PA)
|
|
HAS_BUTTER2 = _bind("qtl_butter2", _PA)
|
|
HAS_BUTTER3 = _bind("qtl_butter3", _PA)
|
|
HAS_CHEBY1 = _bind("qtl_cheby1", _PA)
|
|
HAS_CHEBY2 = _bind("qtl_cheby2", _PA)
|
|
HAS_ELLIPTIC = _bind("qtl_elliptic", _PA)
|
|
HAS_EDCF = _bind("qtl_edcf", _PA)
|
|
HAS_BPF = _bind("qtl_bpf", _PA)
|
|
HAS_ALAGUERRE = _bind("qtl_alaguerre", [_dp, _ci, _dp, _ci, _ci]) # period, order
|
|
HAS_BILATERAL = _bind("qtl_bilateral", [_dp, _ci, _dp, _ci, _cd, _cd]) # period, sigmaS, sigmaR
|
|
HAS_BAXTERKING = _bind("qtl_baxterking", [_dp, _ci, _dp, _ci, _ci, _ci]) # period, minP, maxP
|
|
HAS_CFITZ = _bind("qtl_cfitz", [_dp, _ci, _dp, _ci, _ci]) # period, bandwidthP
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.12 Cycles
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_CG = _bind("qtl_cg", _PA)
|
|
HAS_DSP = _bind("qtl_dsp", _PA)
|
|
HAS_CCOR = _bind("qtl_ccor", _PA)
|
|
HAS_EBSW = _bind("qtl_ebsw", [_dp, _ci, _dp, _ci, _ci]) # period, hpPeriod
|
|
HAS_EACP = _bind("qtl_eacp", [_dp, _ci, _dp, _ci, _ci, _ci, _ci]) # period, minP, maxP, useMedian
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# §8.14 Numerics
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
HAS_CHANGE = _bind("qtl_change", _PA)
|
|
HAS_EXPTRANS = _bind("qtl_exptrans", _PA3) # no period
|
|
HAS_BETADIST = _bind("qtl_betadist", [_dp, _ci, _dp, _ci, _cd, _cd]) # period, alpha, beta
|
|
HAS_EXPDIST = _bind("qtl_expdist", [_dp, _ci, _dp, _ci, _cd]) # period, lambda
|
|
HAS_BINOMDIST = _bind("qtl_binomdist", [_dp, _ci, _dp, _ci, _ci, _ci]) # period, trials, successes
|
|
HAS_CWT = _bind("qtl_cwt", [_dp, _ci, _dp, _cd, _cd]) # scale, omega
|
|
HAS_DWT = _bind("qtl_dwt", [_dp, _ci, _dp, _ci, _ci]) # period, levels
|