mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-28 17:57:45 +00:00
1708 lines
73 KiB
Python
1708 lines
73 KiB
Python
#!/usr/bin/env python3
|
|
"""Complete the Python bridge by adding all Exports.cs (manual) bindings and wrappers.
|
|
|
|
This script:
|
|
1. Rewrites _bridge.py with ALL bindings (Generated + Manual)
|
|
2. Appends missing wrappers to each category .py file
|
|
3. Rewrites indicators.py as thin re-export
|
|
4. Updates __init__.py
|
|
"""
|
|
import os
|
|
import sys
|
|
|
|
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
PKG = os.path.join(ROOT, "quantalib")
|
|
|
|
|
|
def write(path: str, content: str) -> None:
|
|
with open(path, "w", encoding="utf-8", newline="\n") as f:
|
|
f.write(content)
|
|
print(f" wrote {os.path.relpath(path, ROOT)}")
|
|
|
|
|
|
def append(path: str, content: str) -> None:
|
|
with open(path, "a", encoding="utf-8", newline="\n") as f:
|
|
f.write(content)
|
|
print(f" appended to {os.path.relpath(path, ROOT)}")
|
|
|
|
|
|
def read(path: str) -> str:
|
|
with open(path, "r", encoding="utf-8") as f:
|
|
return f.read()
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Step 1: Read existing _bridge.py and add missing manual bindings
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
print("Step 1: Adding missing bindings to _bridge.py ...")
|
|
|
|
bridge_path = os.path.join(PKG, "_bridge.py")
|
|
bridge = read(bridge_path)
|
|
|
|
# Check which bindings already exist
|
|
MANUAL_BINDINGS = {
|
|
# ── Core ──
|
|
"qtl_avgprice": ["{dp}", "{dp}", "{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_medprice": ["{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_typprice": ["{dp}", "{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_midbody": ["{dp}", "{dp}", "{ci}", "{dp}"],
|
|
# ── Momentum ──
|
|
"qtl_rsi": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_roc": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_mom": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_cmo": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_tsi": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_apo": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_bias": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_cfo": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_cfb": ["{dp}", "{ci}", "{dp}", "{ip}", "{ci}"],
|
|
"qtl_asi": ["{dp}", "{dp}", "{dp}", "{dp}", "{ci}", "{dp}", "{cd}"],
|
|
# ── Oscillators ──
|
|
"qtl_fisher": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_fisher04": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_dpo": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_trix": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_inertia": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_rsx": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_er": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_cti": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_reflex": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_trendflex": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_kri": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_psl": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_deco": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_dosc": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}", "{ci}"],
|
|
"qtl_dymoi": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}", "{ci}", "{ci}"],
|
|
"qtl_crsi": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}"],
|
|
"qtl_bbb": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_bbi": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}", "{ci}"],
|
|
"qtl_dem": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_brar": ["{dp}", "{dp}", "{dp}", "{dp}", "{ci}", "{dp}", "{dp}", "{ci}"],
|
|
# ── Trends FIR ──
|
|
"qtl_sma": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_wma": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_hma": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_trima": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_swma": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_dwma": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_blma": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_alma": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}", "{cd}"],
|
|
"qtl_lsma": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{cd}"],
|
|
"qtl_sgma": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_sinema": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_hanma": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_parzen": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_tsf": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_conv": ["{dp}", "{ci}", "{dp}", "{dp}", "{ci}"],
|
|
"qtl_bwma": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_crma": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_sp15": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_tukey_w": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_rain": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_afirma": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}"],
|
|
# ── Trends IIR ──
|
|
"qtl_ema": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_ema_alpha": ["{dp}", "{ci}", "{dp}", "{cd}"],
|
|
"qtl_dema": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_dema_alpha":["{dp}", "{ci}", "{dp}", "{cd}"],
|
|
"qtl_tema": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_lema": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_hema": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_ahrens": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_decycler": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_dsma": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_gdema": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_coral": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_agc": ["{dp}", "{ci}", "{dp}", "{cd}"],
|
|
"qtl_ccyc": ["{dp}", "{ci}", "{dp}", "{cd}"],
|
|
# ── Channels ──
|
|
"qtl_bbands": ["{dp}", "{ci}", "{dp}", "{dp}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_aberr": ["{dp}", "{ci}", "{dp}", "{dp}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_atrbands": ["{dp}", "{dp}", "{dp}", "{ci}", "{dp}", "{dp}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_apchannel": ["{dp}", "{dp}", "{ci}", "{dp}", "{dp}", "{cd}"],
|
|
# ── Volatility ──
|
|
"qtl_tr": ["{dp}", "{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_bbw": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_bbwn": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}", "{ci}"],
|
|
"qtl_bbwp": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}", "{ci}"],
|
|
"qtl_stddev": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_variance": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_etherm": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_ccv": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_cv": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}", "{cd}"],
|
|
"qtl_cvi": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_ewma": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}"],
|
|
# ── Volume ──
|
|
"qtl_obv": ["{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_pvt": ["{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_pvr": ["{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_vf": ["{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_nvi": ["{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_pvi": ["{dp}", "{dp}", "{ci}", "{dp}"],
|
|
"qtl_tvi": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_pvd": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_vwma": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_evwma": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_efi": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_aobv": ["{dp}", "{dp}", "{ci}", "{dp}", "{dp}"],
|
|
"qtl_mfi": ["{dp}", "{dp}", "{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_cmf": ["{dp}", "{dp}", "{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_eom": ["{dp}", "{dp}", "{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_pvo": ["{dp}", "{ci}", "{dp}", "{dp}", "{dp}", "{ci}", "{ci}", "{ci}"],
|
|
# ── Statistics ──
|
|
"qtl_zscore": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_cma": ["{dp}", "{ci}", "{dp}"],
|
|
"qtl_entropy": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_correlation": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_covariance": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_cointegration": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
# ── Errors ──
|
|
"qtl_mse": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_rmse": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_mae": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_mape": ["{dp}", "{dp}", "{ci}", "{dp}", "{ci}"],
|
|
# ── Filters ──
|
|
"qtl_bessel": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_butter2": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_butter3": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_cheby1": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_cheby2": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_elliptic": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_edcf": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_bpf": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_alaguerre": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_bilateral": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}", "{cd}"],
|
|
"qtl_baxterking": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}"],
|
|
"qtl_cfitz": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
# ── Cycles ──
|
|
"qtl_cg": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_dsp": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_ccor": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_ebsw": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
"qtl_eacp": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}", "{ci}"],
|
|
# ── Numerics ──
|
|
"qtl_change": ["{dp}", "{ci}", "{dp}", "{ci}"],
|
|
"qtl_exptrans": ["{dp}", "{ci}", "{dp}"],
|
|
"qtl_betadist": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}", "{cd}"],
|
|
"qtl_expdist": ["{dp}", "{ci}", "{dp}", "{ci}", "{cd}"],
|
|
"qtl_binomdist":["{dp}", "{ci}", "{dp}", "{ci}", "{ci}", "{ci}"],
|
|
"qtl_cwt": ["{dp}", "{ci}", "{dp}", "{cd}", "{cd}"],
|
|
"qtl_dwt": ["{dp}", "{ci}", "{dp}", "{ci}", "{ci}"],
|
|
}
|
|
|
|
# Build binding lines
|
|
TYPE_MAP = {"{dp}": "_dp", "{ci}": "_ci", "{cd}": "_cd", "{ip}": "_ip"}
|
|
|
|
missing_bindings = {} # category -> list of lines
|
|
categories_order = [
|
|
("Core", ["qtl_avgprice","qtl_medprice","qtl_typprice","qtl_midbody"]),
|
|
("Momentum", ["qtl_rsi","qtl_roc","qtl_mom","qtl_cmo","qtl_tsi","qtl_apo","qtl_bias","qtl_cfo","qtl_cfb","qtl_asi"]),
|
|
("Oscillators", ["qtl_fisher","qtl_fisher04","qtl_dpo","qtl_trix","qtl_inertia","qtl_rsx","qtl_er","qtl_cti","qtl_reflex","qtl_trendflex","qtl_kri","qtl_psl","qtl_deco","qtl_dosc","qtl_dymoi","qtl_crsi","qtl_bbb","qtl_bbi","qtl_dem","qtl_brar"]),
|
|
("Trends — FIR", ["qtl_sma","qtl_wma","qtl_hma","qtl_trima","qtl_swma","qtl_dwma","qtl_blma","qtl_alma","qtl_lsma","qtl_sgma","qtl_sinema","qtl_hanma","qtl_parzen","qtl_tsf","qtl_conv","qtl_bwma","qtl_crma","qtl_sp15","qtl_tukey_w","qtl_rain","qtl_afirma"]),
|
|
("Trends — IIR", ["qtl_ema","qtl_ema_alpha","qtl_dema","qtl_dema_alpha","qtl_tema","qtl_lema","qtl_hema","qtl_ahrens","qtl_decycler","qtl_dsma","qtl_gdema","qtl_coral","qtl_agc","qtl_ccyc"]),
|
|
("Channels", ["qtl_bbands","qtl_aberr","qtl_atrbands","qtl_apchannel"]),
|
|
("Volatility", ["qtl_tr","qtl_bbw","qtl_bbwn","qtl_bbwp","qtl_stddev","qtl_variance","qtl_etherm","qtl_ccv","qtl_cv","qtl_cvi","qtl_ewma"]),
|
|
("Volume", ["qtl_obv","qtl_pvt","qtl_pvr","qtl_vf","qtl_nvi","qtl_pvi","qtl_tvi","qtl_pvd","qtl_vwma","qtl_evwma","qtl_efi","qtl_aobv","qtl_mfi","qtl_cmf","qtl_eom","qtl_pvo"]),
|
|
("Statistics", ["qtl_zscore","qtl_cma","qtl_entropy","qtl_correlation","qtl_covariance","qtl_cointegration"]),
|
|
("Errors", ["qtl_mse","qtl_rmse","qtl_mae","qtl_mape"]),
|
|
("Filters", ["qtl_bessel","qtl_butter2","qtl_butter3","qtl_cheby1","qtl_cheby2","qtl_elliptic","qtl_edcf","qtl_bpf","qtl_alaguerre","qtl_bilateral","qtl_baxterking","qtl_cfitz"]),
|
|
("Cycles", ["qtl_cg","qtl_dsp","qtl_ccor","qtl_ebsw","qtl_eacp"]),
|
|
("Numerics", ["qtl_change","qtl_exptrans","qtl_betadist","qtl_expdist","qtl_binomdist","qtl_cwt","qtl_dwt"]),
|
|
]
|
|
|
|
added_count = 0
|
|
new_lines = []
|
|
for cat, names in categories_order:
|
|
cat_lines = []
|
|
for name in names:
|
|
if f'"{name}"' in bridge:
|
|
continue # already bound
|
|
args = MANUAL_BINDINGS[name]
|
|
arg_str = ", ".join(TYPE_MAP[a] for a in args)
|
|
var = "HAS_" + name.replace("qtl_", "").upper()
|
|
cat_lines.append(f'{var} = _bind("{name}", [{arg_str}])')
|
|
added_count += 1
|
|
if cat_lines:
|
|
new_lines.append(f"\n# ── {cat} (Exports.cs — manual) ──")
|
|
new_lines.extend(cat_lines)
|
|
|
|
if new_lines:
|
|
# Append to end of _bridge.py
|
|
with open(bridge_path, "a", encoding="utf-8", newline="\n") as f:
|
|
f.write("\n")
|
|
f.write("\n".join(new_lines))
|
|
f.write("\n")
|
|
print(f" Added {added_count} bindings to _bridge.py")
|
|
else:
|
|
print(" All bindings already present in _bridge.py")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Step 2: Add missing wrappers to category .py files
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
print("\nStep 2: Adding missing wrappers to category files ...")
|
|
|
|
# For each category file, check what's in __all__ and add missing funcs
|
|
|
|
|
|
# ── core.py ──
|
|
core_additions = '''
|
|
|
|
def avgprice(open: object, high: object, low: object, close: object,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Average Price = (O+H+L+C)/4."""
|
|
offset = int(offset)
|
|
o, idx = _arr(open); h, _ = _arr(high); l, _ = _arr(low); c, _ = _arr(close)
|
|
n = len(o); dst = _out(n)
|
|
_check(_lib.qtl_avgprice(_ptr(o), _ptr(h), _ptr(l), _ptr(c), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "AVGPRICE", "core", offset)
|
|
|
|
|
|
def medprice(high: object, low: object, offset: int = 0, **kwargs) -> object:
|
|
"""Median Price = (H+L)/2."""
|
|
h, idx = _arr(high); l, _ = _arr(low)
|
|
n = len(h); dst = _out(n)
|
|
_check(_lib.qtl_medprice(_ptr(h), _ptr(l), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "MEDPRICE", "core", int(offset))
|
|
|
|
|
|
def typprice(open: object, high: object, low: object,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Typical Price = (O+H+L)/3 (QuanTAlib variant)."""
|
|
o, idx = _arr(open); h, _ = _arr(high); l, _ = _arr(low)
|
|
n = len(o); dst = _out(n)
|
|
_check(_lib.qtl_typprice(_ptr(o), _ptr(h), _ptr(l), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "TYPPRICE", "core", int(offset))
|
|
|
|
|
|
def midbody(open: object, close: object, offset: int = 0, **kwargs) -> object:
|
|
"""Mid Body = (O+C)/2."""
|
|
o, idx = _arr(open); c, _ = _arr(close)
|
|
n = len(o); dst = _out(n)
|
|
_check(_lib.qtl_midbody(_ptr(o), _ptr(c), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "MIDBODY", "core", int(offset))
|
|
'''
|
|
|
|
|
|
# ── momentum.py ──
|
|
momentum_additions = '''
|
|
import ctypes
|
|
|
|
|
|
def rsi(close: object, length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Relative Strength Index."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_rsi(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"RSI_{length}", "momentum", offset)
|
|
|
|
|
|
def roc(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Rate of Change."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_roc(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"ROC_{length}", "momentum", offset)
|
|
|
|
|
|
def mom(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Momentum."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_mom(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"MOM_{length}", "momentum", offset)
|
|
|
|
|
|
def cmo(close: object, length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Chande Momentum Oscillator."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cmo(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"CMO_{length}", "momentum", offset)
|
|
|
|
|
|
def tsi(close: object, long_period: int = 25, short_period: int = 13,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""True Strength Index."""
|
|
long_period = int(long_period); short_period = int(short_period); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_tsi(_ptr(src), n, _ptr(dst), long_period, short_period))
|
|
return _wrap(dst, idx, f"TSI_{long_period}_{short_period}", "momentum", offset)
|
|
|
|
|
|
def apo(close: object, fast: int = 12, slow: int = 26,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Absolute Price Oscillator."""
|
|
fast = int(fast); slow = int(slow); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_apo(_ptr(src), n, _ptr(dst), fast, slow))
|
|
return _wrap(dst, idx, f"APO_{fast}_{slow}", "momentum", offset)
|
|
|
|
|
|
def bias(close: object, length: int = 26, offset: int = 0, **kwargs) -> object:
|
|
"""Bias."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bias(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"BIAS_{length}", "momentum", offset)
|
|
|
|
|
|
def cfo(close: object, length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Chande Forecast Oscillator."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cfo(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"CFO_{length}", "momentum", offset)
|
|
|
|
|
|
def cfb(close: object, lengths: list | None = None,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Composite Fractal Behavior."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
if lengths:
|
|
arr_t = (ctypes.c_int * len(lengths))(*lengths)
|
|
_check(_lib.qtl_cfb(_ptr(src), n, _ptr(dst), arr_t, len(lengths)))
|
|
else:
|
|
_check(_lib.qtl_cfb(_ptr(src), n, _ptr(dst), None, 0))
|
|
return _wrap(dst, idx, "CFB", "momentum", offset)
|
|
|
|
|
|
def asi(open: object, high: object, low: object, close: object,
|
|
limit: float = 3.0, offset: int = 0, **kwargs) -> object:
|
|
"""Accumulative Swing Index."""
|
|
o, idx = _arr(open); h, _ = _arr(high); l, _ = _arr(low); c, _ = _arr(close)
|
|
n = len(o); dst = _out(n)
|
|
_check(_lib.qtl_asi(_ptr(o), _ptr(h), _ptr(l), _ptr(c), n, _ptr(dst), float(limit)))
|
|
return _wrap(dst, idx, "ASI", "momentum", int(offset))
|
|
'''
|
|
|
|
|
|
# ── oscillators.py ──
|
|
oscillators_additions = '''
|
|
|
|
def fisher(close: object, length: int = 9, offset: int = 0, **kwargs) -> object:
|
|
"""Fisher Transform."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_fisher(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"FISHER_{length}", "oscillators", offset)
|
|
|
|
|
|
def fisher04(close: object, length: int = 9, offset: int = 0, **kwargs) -> object:
|
|
"""Fisher Transform (0.4 variant)."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_fisher04(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"FISHER04_{length}", "oscillators", offset)
|
|
|
|
|
|
def dpo(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Detrended Price Oscillator."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dpo(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"DPO_{length}", "oscillators", offset)
|
|
|
|
|
|
def trix(close: object, length: int = 18, offset: int = 0, **kwargs) -> object:
|
|
"""Triple EMA Rate of Change."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_trix(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"TRIX_{length}", "oscillators", offset)
|
|
|
|
|
|
def inertia(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Inertia."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_inertia(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"INERTIA_{length}", "oscillators", offset)
|
|
|
|
|
|
def rsx(close: object, length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Relative Strength Xtra."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_rsx(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"RSX_{length}", "oscillators", offset)
|
|
|
|
|
|
def er(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Efficiency Ratio."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_er(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"ER_{length}", "oscillators", offset)
|
|
|
|
|
|
def cti(close: object, length: int = 12, offset: int = 0, **kwargs) -> object:
|
|
"""Correlation Trend Indicator."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cti(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"CTI_{length}", "oscillators", offset)
|
|
|
|
|
|
def reflex(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Reflex."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_reflex(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"REFLEX_{length}", "oscillators", offset)
|
|
|
|
|
|
def trendflex(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Trendflex."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_trendflex(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"TRENDFLEX_{length}", "oscillators", offset)
|
|
|
|
|
|
def kri(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Kairi Relative Index."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_kri(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"KRI_{length}", "oscillators", offset)
|
|
|
|
|
|
def psl(close: object, length: int = 12, offset: int = 0, **kwargs) -> object:
|
|
"""Psychological Line."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_psl(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"PSL_{length}", "oscillators", offset)
|
|
|
|
|
|
def deco(close: object, short_period: int = 30, long_period: int = 60,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""DECO."""
|
|
short_period = int(short_period); long_period = int(long_period); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_deco(_ptr(src), n, _ptr(dst), short_period, long_period))
|
|
return _wrap(dst, idx, f"DECO_{short_period}_{long_period}", "oscillators", offset)
|
|
|
|
|
|
def dosc(close: object, rsi_period: int = 14, ema1_period: int = 5,
|
|
ema2_period: int = 3, signal_period: int = 9,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""DeMarker Oscillator."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dosc(_ptr(src), n, _ptr(dst),
|
|
int(rsi_period), int(ema1_period), int(ema2_period), int(signal_period)))
|
|
return _wrap(dst, idx, f"DOSC_{rsi_period}", "oscillators", offset)
|
|
|
|
|
|
def dymoi(close: object, base_period: int = 14, short_period: int = 5,
|
|
long_period: int = 10, min_period: int = 3, max_period: int = 30,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Dynamic Momentum Index."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dymoi(_ptr(src), n, _ptr(dst),
|
|
int(base_period), int(short_period), int(long_period),
|
|
int(min_period), int(max_period)))
|
|
return _wrap(dst, idx, "DYMOI", "oscillators", offset)
|
|
|
|
|
|
def crsi(close: object, rsi_period: int = 3, streak_period: int = 2,
|
|
rank_period: int = 100, offset: int = 0, **kwargs) -> object:
|
|
"""Connors RSI."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_crsi(_ptr(src), n, _ptr(dst),
|
|
int(rsi_period), int(streak_period), int(rank_period)))
|
|
return _wrap(dst, idx, f"CRSI_{rsi_period}", "oscillators", offset)
|
|
|
|
|
|
def bbb(close: object, length: int = 20, mult: float = 2.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Bollinger Band Bounce."""
|
|
length = int(length); mult = float(mult); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bbb(_ptr(src), n, _ptr(dst), length, mult))
|
|
return _wrap(dst, idx, f"BBB_{length}", "oscillators", offset)
|
|
|
|
|
|
def bbi(close: object, p1: int = 3, p2: int = 6, p3: int = 12, p4: int = 24,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Bull Bear Index."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bbi(_ptr(src), n, _ptr(dst), int(p1), int(p2), int(p3), int(p4)))
|
|
return _wrap(dst, idx, "BBI", "oscillators", offset)
|
|
|
|
|
|
def dem(high: object, low: object, length: int = 14,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""DeMarker."""
|
|
length = int(length)
|
|
h, idx = _arr(high); l, _ = _arr(low)
|
|
n = len(h); dst = _out(n)
|
|
_check(_lib.qtl_dem(_ptr(h), _ptr(l), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"DEM_{length}", "oscillators", int(offset))
|
|
|
|
|
|
def brar(open: object, high: object, low: object, close: object,
|
|
length: int = 26, offset: int = 0, **kwargs) -> object:
|
|
"""Bull-Bear Ratio (BRAR)."""
|
|
length = int(length); offset = int(offset)
|
|
o, idx = _arr(open); h, _ = _arr(high); l, _ = _arr(low); c, _ = _arr(close)
|
|
n = len(o); br = _out(n); ar = _out(n)
|
|
_check(_lib.qtl_brar(_ptr(o), _ptr(h), _ptr(l), _ptr(c), n, _ptr(br), _ptr(ar), length))
|
|
return _wrap_multi({f"BR_{length}": br, f"AR_{length}": ar}, idx, "oscillators", offset)
|
|
'''
|
|
|
|
|
|
# ── trends_fir.py ──
|
|
trends_fir_additions = '''
|
|
import numpy as np
|
|
|
|
_F64 = np.float64
|
|
|
|
|
|
def sma(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Simple Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_sma(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"SMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def wma(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_wma(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"WMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def hma(close: object, length: int = 9, offset: int = 0, **kwargs) -> object:
|
|
"""Hull Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_hma(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"HMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def trima(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Triangular Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_trima(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"TRIMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def swma(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Symmetric Weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_swma(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"SWMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def dwma(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Double Weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dwma(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"DWMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def blma(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Blackman Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_blma(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"BLMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def alma(close: object, length: int = 10, alma_offset: float = 0.85,
|
|
sigma: float = 6.0, offset: int = 0, **kwargs) -> object:
|
|
"""Arnaud Legoux Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_alma(_ptr(src), n, _ptr(dst), length, float(alma_offset), float(sigma)))
|
|
return _wrap(dst, idx, f"ALMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def lsma(close: object, length: int = 25, offset: int = 0, **kwargs) -> object:
|
|
"""Least Squares Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_lsma(_ptr(src), n, _ptr(dst), length, 0, 1.0))
|
|
return _wrap(dst, idx, f"LSMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def sgma(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Savitzky-Golay Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_sgma(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"SGMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def sinema(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Sine-weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_sinema(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"SINEMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def hanma(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Hann-weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_hanma(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"HANMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def parzen(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Parzen-weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_parzen(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"PARZEN_{length}", "trends_fir", offset)
|
|
|
|
|
|
def tsf(close: object, length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Time Series Forecast."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_tsf(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"TSF_{length}", "trends_fir", offset)
|
|
|
|
|
|
def conv(close: object, kernel: list | None = None,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Convolution with custom kernel."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
if kernel is None:
|
|
kernel = [1.0]
|
|
k = np.ascontiguousarray(kernel, dtype=_F64)
|
|
_check(_lib.qtl_conv(_ptr(src), n, _ptr(dst), _ptr(k), len(k)))
|
|
return _wrap(dst, idx, "CONV", "trends_fir", offset)
|
|
|
|
|
|
def bwma(close: object, length: int = 10, order: int = 0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Butterworth-weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bwma(_ptr(src), n, _ptr(dst), length, int(order)))
|
|
return _wrap(dst, idx, f"BWMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def crma(close: object, length: int = 10, volume_factor: float = 1.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Cosine-Ramp Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_crma(_ptr(src), n, _ptr(dst), length, float(volume_factor)))
|
|
return _wrap(dst, idx, f"CRMA_{length}", "trends_fir", offset)
|
|
|
|
|
|
def sp15(close: object, length: int = 15, offset: int = 0, **kwargs) -> object:
|
|
"""SP-15 Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_sp15(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"SP15_{length}", "trends_fir", offset)
|
|
|
|
|
|
def tukey_w(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Tukey-windowed Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_tukey_w(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"TUKEY_{length}", "trends_fir", offset)
|
|
|
|
|
|
def rain(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""RAIN Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_rain(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"RAIN_{length}", "trends_fir", offset)
|
|
|
|
|
|
def afirma(close: object, length: int = 10, window_type: int = 0,
|
|
use_simd: bool = False, offset: int = 0, **kwargs) -> object:
|
|
"""Adaptive FIR Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_afirma(_ptr(src), n, _ptr(dst), length, int(window_type), int(use_simd)))
|
|
return _wrap(dst, idx, f"AFIRMA_{length}", "trends_fir", offset)
|
|
'''
|
|
|
|
|
|
# ── trends_iir.py ──
|
|
trends_iir_additions = '''
|
|
|
|
def ema(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Exponential Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_ema(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"EMA_{length}", "trends_iir", offset)
|
|
|
|
|
|
def ema_alpha(close: object, alpha: float = 0.1, offset: int = 0, **kwargs) -> object:
|
|
"""EMA with explicit alpha."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_ema_alpha(_ptr(src), n, _ptr(dst), float(alpha)))
|
|
return _wrap(dst, idx, f"EMA_a{alpha:.4f}", "trends_iir", offset)
|
|
|
|
|
|
def dema(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Double Exponential Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dema(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"DEMA_{length}", "trends_iir", offset)
|
|
|
|
|
|
def dema_alpha(close: object, alpha: float = 0.1, offset: int = 0, **kwargs) -> object:
|
|
"""DEMA with explicit alpha."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dema_alpha(_ptr(src), n, _ptr(dst), float(alpha)))
|
|
return _wrap(dst, idx, f"DEMA_a{alpha:.4f}", "trends_iir", offset)
|
|
|
|
|
|
def tema(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Triple Exponential Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_tema(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"TEMA_{length}", "trends_iir", offset)
|
|
|
|
|
|
def lema(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Laguerre-based EMA."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_lema(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"LEMA_{length}", "trends_iir", offset)
|
|
|
|
|
|
def hema(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Henderson EMA."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_hema(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"HEMA_{length}", "trends_iir", offset)
|
|
|
|
|
|
def ahrens(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Ahrens Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_ahrens(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"AHRENS_{length}", "trends_iir", offset)
|
|
|
|
|
|
def decycler(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Simple Decycler."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_decycler(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"DECYCLER_{length}", "trends_iir", offset)
|
|
|
|
|
|
def dsma(close: object, length: int = 10, factor: float = 0.5,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Deviation-Scaled Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dsma(_ptr(src), n, _ptr(dst), length, float(factor)))
|
|
return _wrap(dst, idx, f"DSMA_{length}", "trends_iir", offset)
|
|
|
|
|
|
def gdema(close: object, length: int = 10, vfactor: float = 1.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Generalized DEMA."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_gdema(_ptr(src), n, _ptr(dst), length, float(vfactor)))
|
|
return _wrap(dst, idx, f"GDEMA_{length}", "trends_iir", offset)
|
|
|
|
|
|
def coral(close: object, length: int = 10, friction: float = 0.4,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""CORAL Trend."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_coral(_ptr(src), n, _ptr(dst), length, float(friction)))
|
|
return _wrap(dst, idx, f"CORAL_{length}", "trends_iir", offset)
|
|
|
|
|
|
def agc(close: object, alpha: float = 0.1, offset: int = 0, **kwargs) -> object:
|
|
"""Automatic Gain Control."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_agc(_ptr(src), n, _ptr(dst), float(alpha)))
|
|
return _wrap(dst, idx, f"AGC_a{alpha:.4f}", "trends_iir", offset)
|
|
|
|
|
|
def ccyc(close: object, alpha: float = 0.1, offset: int = 0, **kwargs) -> object:
|
|
"""Cyber Cycle."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_ccyc(_ptr(src), n, _ptr(dst), float(alpha)))
|
|
return _wrap(dst, idx, f"CCYC_a{alpha:.4f}", "trends_iir", offset)
|
|
'''
|
|
|
|
|
|
# ── channels.py ──
|
|
channels_additions = '''
|
|
|
|
def bbands(close: object, length: int = 20, std: float = 2.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Bollinger Bands -> (upper, mid, lower) or DataFrame."""
|
|
length = int(length); std = float(std); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src)
|
|
upper = _out(n); mid = _out(n); lower = _out(n)
|
|
_check(_lib.qtl_bbands(_ptr(src), n, _ptr(upper), _ptr(mid), _ptr(lower), length, std))
|
|
return _wrap_multi(
|
|
{f"BBU_{length}_{std}": upper, f"BBM_{length}_{std}": mid, f"BBL_{length}_{std}": lower},
|
|
idx, "channels", offset)
|
|
|
|
|
|
def aberr(close: object, length: int = 20, mult: float = 2.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Aberration Bands -> (upper, mid, lower) or DataFrame."""
|
|
length = int(length); mult = float(mult); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src)
|
|
upper = _out(n); mid = _out(n); lower = _out(n)
|
|
_check(_lib.qtl_aberr(_ptr(src), n, _ptr(mid), _ptr(upper), _ptr(lower), length, mult))
|
|
return _wrap_multi(
|
|
{f"ABERRU_{length}_{mult}": upper, f"ABERRM_{length}_{mult}": mid, f"ABERRL_{length}_{mult}": lower},
|
|
idx, "channels", offset)
|
|
|
|
|
|
def atrbands(high: object, low: object, close: object,
|
|
length: int = 14, mult: float = 2.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""ATR Bands -> (upper, mid, lower) or DataFrame."""
|
|
length = int(length); mult = float(mult); offset = int(offset)
|
|
h, idx = _arr(high); l, _ = _arr(low); c, _ = _arr(close)
|
|
n = len(h)
|
|
upper = _out(n); mid = _out(n); lower = _out(n)
|
|
_check(_lib.qtl_atrbands(_ptr(h), _ptr(l), _ptr(c), n, _ptr(upper), _ptr(mid), _ptr(lower), length, mult))
|
|
return _wrap_multi(
|
|
{f"ATRBU_{length}_{mult}": upper, f"ATRBM_{length}_{mult}": mid, f"ATRBL_{length}_{mult}": lower},
|
|
idx, "channels", offset)
|
|
|
|
|
|
def apchannel(high: object, low: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Average Price Channel -> (upper, lower) or DataFrame."""
|
|
length = int(length); offset = int(offset)
|
|
h, idx = _arr(high); l, _ = _arr(low)
|
|
n = len(h)
|
|
upper = _out(n); lower = _out(n)
|
|
_check(_lib.qtl_apchannel(_ptr(h), _ptr(l), n, _ptr(upper), _ptr(lower), float(length)))
|
|
return _wrap_multi({f"APCU_{length}": upper, f"APCL_{length}": lower}, idx, "channels", offset)
|
|
'''
|
|
|
|
|
|
# ── volatility.py ──
|
|
volatility_additions = '''
|
|
|
|
def tr(high: object, low: object, close: object, offset: int = 0, **kwargs) -> object:
|
|
"""True Range."""
|
|
h, idx = _arr(high); l, _ = _arr(low); c, _ = _arr(close)
|
|
n = len(h); dst = _out(n)
|
|
_check(_lib.qtl_tr(_ptr(h), _ptr(l), _ptr(c), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "TR", "volatility", int(offset))
|
|
|
|
|
|
def bbw(close: object, length: int = 20, mult: float = 2.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Bollinger Band Width."""
|
|
length = int(length); mult = float(mult); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bbw(_ptr(src), n, _ptr(dst), length, mult))
|
|
return _wrap(dst, idx, f"BBW_{length}", "volatility", offset)
|
|
|
|
|
|
def bbwn(close: object, length: int = 20, mult: float = 2.0,
|
|
lookback: int = 252, offset: int = 0, **kwargs) -> object:
|
|
"""Bollinger Band Width Normalized."""
|
|
length = int(length); mult = float(mult); lookback = int(lookback); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bbwn(_ptr(src), n, _ptr(dst), length, mult, lookback))
|
|
return _wrap(dst, idx, f"BBWN_{length}", "volatility", offset)
|
|
|
|
|
|
def bbwp(close: object, length: int = 20, mult: float = 2.0,
|
|
lookback: int = 252, offset: int = 0, **kwargs) -> object:
|
|
"""Bollinger Band Width Percentile."""
|
|
length = int(length); mult = float(mult); lookback = int(lookback); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bbwp(_ptr(src), n, _ptr(dst), length, mult, lookback))
|
|
return _wrap(dst, idx, f"BBWP_{length}", "volatility", offset)
|
|
|
|
|
|
def stddev(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Standard Deviation."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_stddev(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"STDDEV_{length}", "volatility", offset)
|
|
|
|
|
|
def variance(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Variance."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_variance(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"VAR_{length}", "volatility", offset)
|
|
|
|
|
|
def etherm(high: object, low: object, length: int = 14,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Elder Thermometer."""
|
|
length = int(length)
|
|
h, idx = _arr(high); l, _ = _arr(low)
|
|
n = len(h); dst = _out(n)
|
|
_check(_lib.qtl_etherm(_ptr(h), _ptr(l), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"ETHERM_{length}", "volatility", int(offset))
|
|
|
|
|
|
def ccv(close: object, short_period: int = 20, long_period: int = 1,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Close-to-Close Volatility."""
|
|
short_period = int(short_period); long_period = int(long_period); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_ccv(_ptr(src), n, _ptr(dst), short_period, long_period))
|
|
return _wrap(dst, idx, f"CCV_{short_period}", "volatility", offset)
|
|
|
|
|
|
def cv(close: object, length: int = 20, min_vol: float = 0.2,
|
|
max_vol: float = 0.7, offset: int = 0, **kwargs) -> object:
|
|
"""Coefficient of Variation."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cv(_ptr(src), n, _ptr(dst), length, float(min_vol), float(max_vol)))
|
|
return _wrap(dst, idx, f"CV_{length}", "volatility", offset)
|
|
|
|
|
|
def cvi(close: object, ema_period: int = 10, roc_period: int = 10,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Chaikin Volatility Index."""
|
|
ema_period = int(ema_period); roc_period = int(roc_period); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cvi(_ptr(src), n, _ptr(dst), ema_period, roc_period))
|
|
return _wrap(dst, idx, f"CVI_{ema_period}", "volatility", offset)
|
|
|
|
|
|
def ewma(close: object, length: int = 20, is_pop: int = 1,
|
|
ann_factor: int = 252, offset: int = 0, **kwargs) -> object:
|
|
"""Exponentially Weighted Moving Average (volatility)."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_ewma(_ptr(src), n, _ptr(dst), length, int(is_pop), int(ann_factor)))
|
|
return _wrap(dst, idx, f"EWMA_{length}", "volatility", offset)
|
|
'''
|
|
|
|
|
|
# ── volume.py ──
|
|
volume_additions = '''
|
|
|
|
def obv(close: object, volume: object, offset: int = 0, **kwargs) -> object:
|
|
"""On-Balance Volume."""
|
|
offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_obv(_ptr(c), _ptr(v), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "OBV", "volume", offset)
|
|
|
|
|
|
def pvt(close: object, volume: object, offset: int = 0, **kwargs) -> object:
|
|
"""Price Volume Trend."""
|
|
offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_pvt(_ptr(c), _ptr(v), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "PVT", "volume", offset)
|
|
|
|
|
|
def pvr(close: object, volume: object, offset: int = 0, **kwargs) -> object:
|
|
"""Price Volume Rank."""
|
|
offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_pvr(_ptr(c), _ptr(v), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "PVR", "volume", offset)
|
|
|
|
|
|
def vf(close: object, volume: object, offset: int = 0, **kwargs) -> object:
|
|
"""Volume Flow."""
|
|
offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_vf(_ptr(c), _ptr(v), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "VF", "volume", offset)
|
|
|
|
|
|
def nvi(close: object, volume: object, offset: int = 0, **kwargs) -> object:
|
|
"""Negative Volume Index."""
|
|
offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_nvi(_ptr(c), _ptr(v), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "NVI", "volume", offset)
|
|
|
|
|
|
def pvi(close: object, volume: object, offset: int = 0, **kwargs) -> object:
|
|
"""Positive Volume Index."""
|
|
offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_pvi(_ptr(c), _ptr(v), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "PVI", "volume", offset)
|
|
|
|
|
|
def tvi(close: object, volume: object, length: int = 14,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Trade Volume Index."""
|
|
length = int(length); offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_tvi(_ptr(c), _ptr(v), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"TVI_{length}", "volume", offset)
|
|
|
|
|
|
def pvd(close: object, volume: object, length: int = 14,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Price Volume Divergence."""
|
|
length = int(length); offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_pvd(_ptr(c), _ptr(v), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"PVD_{length}", "volume", offset)
|
|
|
|
|
|
def vwma(close: object, volume: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Volume Weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_vwma(_ptr(c), _ptr(v), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"VWMA_{length}", "volume", offset)
|
|
|
|
|
|
def evwma(close: object, volume: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Elastic Volume Weighted Moving Average."""
|
|
length = int(length); offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_evwma(_ptr(c), _ptr(v), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"EVWMA_{length}", "volume", offset)
|
|
|
|
|
|
def efi(close: object, volume: object, length: int = 13,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Elder Force Index."""
|
|
length = int(length); offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); dst = _out(n)
|
|
_check(_lib.qtl_efi(_ptr(c), _ptr(v), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"EFI_{length}", "volume", offset)
|
|
|
|
|
|
def aobv(close: object, volume: object, offset: int = 0, **kwargs) -> object:
|
|
"""Archer OBV -> (fast, slow) or DataFrame."""
|
|
offset = int(offset)
|
|
c, idx = _arr(close); v, _ = _arr(volume)
|
|
n = len(c); obv_out = _out(n); sig = _out(n)
|
|
_check(_lib.qtl_aobv(_ptr(c), _ptr(v), n, _ptr(obv_out), _ptr(sig)))
|
|
return _wrap_multi({"AOBV": obv_out, "AOBV_SIG": sig}, idx, "volume", offset)
|
|
|
|
|
|
def mfi(high: object, low: object, close: object, volume: object,
|
|
length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Money Flow Index."""
|
|
length = int(length); offset = int(offset)
|
|
h, idx = _arr(high); l, _ = _arr(low); c, _ = _arr(close); v, _ = _arr(volume)
|
|
n = len(h); dst = _out(n)
|
|
_check(_lib.qtl_mfi(_ptr(h), _ptr(l), _ptr(c), _ptr(v), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"MFI_{length}", "volume", offset)
|
|
|
|
|
|
def cmf(high: object, low: object, close: object, volume: object,
|
|
length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Chaikin Money Flow."""
|
|
length = int(length); offset = int(offset)
|
|
h, idx = _arr(high); l, _ = _arr(low); c, _ = _arr(close); v, _ = _arr(volume)
|
|
n = len(h); dst = _out(n)
|
|
_check(_lib.qtl_cmf(_ptr(h), _ptr(l), _ptr(c), _ptr(v), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"CMF_{length}", "volume", offset)
|
|
|
|
|
|
def eom(high: object, low: object, volume: object,
|
|
length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Ease of Movement."""
|
|
length = int(length); offset = int(offset)
|
|
h, idx = _arr(high); l, _ = _arr(low); v, _ = _arr(volume)
|
|
n = len(h); dst = _out(n)
|
|
_check(_lib.qtl_eom(_ptr(h), _ptr(l), _ptr(v), n, _ptr(dst), length, 1e9))
|
|
return _wrap(dst, idx, f"EOM_{length}", "volume", offset)
|
|
|
|
|
|
def pvo(volume: object, fast: int = 12, slow: int = 26, signal: int = 9,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Percentage Volume Oscillator -> (pvo, signal, histogram) or DataFrame."""
|
|
fast = int(fast); slow = int(slow); signal = int(signal); offset = int(offset)
|
|
v, idx = _arr(volume); n = len(v)
|
|
pvo_out = _out(n); sig = _out(n); hist = _out(n)
|
|
_check(_lib.qtl_pvo(_ptr(v), n, _ptr(pvo_out), _ptr(sig), _ptr(hist), fast, slow, signal))
|
|
return _wrap_multi(
|
|
{f"PVO_{fast}_{slow}_{signal}": pvo_out, f"PVOs_{fast}_{slow}_{signal}": sig, f"PVOh_{fast}_{slow}_{signal}": hist},
|
|
idx, "volume", offset)
|
|
'''
|
|
|
|
|
|
# ── statistics.py ──
|
|
statistics_additions = '''
|
|
|
|
def zscore(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Z-Score."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_zscore(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"ZSCORE_{length}", "statistics", offset)
|
|
|
|
|
|
def cma(close: object, offset: int = 0, **kwargs) -> object:
|
|
"""Cumulative Moving Average."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cma(_ptr(src), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "CMA", "statistics", offset)
|
|
|
|
|
|
def entropy(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Shannon Entropy."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_entropy(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"ENTROPY_{length}", "statistics", offset)
|
|
|
|
|
|
def correlation(x: object, y: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Pearson Correlation."""
|
|
length = int(length); offset = int(offset)
|
|
xarr, idx = _arr(x); yarr, _ = _arr(y)
|
|
n = len(xarr); dst = _out(n)
|
|
_check(_lib.qtl_correlation(_ptr(xarr), _ptr(yarr), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"CORR_{length}", "statistics", offset)
|
|
|
|
|
|
def covariance(x: object, y: object, length: int = 20,
|
|
is_sample: bool = True, offset: int = 0, **kwargs) -> object:
|
|
"""Covariance."""
|
|
length = int(length); offset = int(offset)
|
|
xarr, idx = _arr(x); yarr, _ = _arr(y)
|
|
n = len(xarr); dst = _out(n)
|
|
_check(_lib.qtl_covariance(_ptr(xarr), _ptr(yarr), n, _ptr(dst), length, int(is_sample)))
|
|
return _wrap(dst, idx, f"COV_{length}", "statistics", offset)
|
|
|
|
|
|
def cointegration(x: object, y: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Cointegration."""
|
|
length = int(length); offset = int(offset)
|
|
xarr, idx = _arr(x); yarr, _ = _arr(y)
|
|
n = len(xarr); dst = _out(n)
|
|
_check(_lib.qtl_cointegration(_ptr(xarr), _ptr(yarr), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"COINT_{length}", "statistics", offset)
|
|
'''
|
|
|
|
|
|
# ── errors.py ──
|
|
errors_additions = '''
|
|
|
|
def mse(actual: object, predicted: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Mean Squared Error."""
|
|
length = int(length); offset = int(offset)
|
|
a, idx = _arr(actual); p, _ = _arr(predicted)
|
|
n = len(a); dst = _out(n)
|
|
_check(_lib.qtl_mse(_ptr(a), _ptr(p), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"MSE_{length}", "errors", offset)
|
|
|
|
|
|
def rmse(actual: object, predicted: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Root Mean Squared Error."""
|
|
length = int(length); offset = int(offset)
|
|
a, idx = _arr(actual); p, _ = _arr(predicted)
|
|
n = len(a); dst = _out(n)
|
|
_check(_lib.qtl_rmse(_ptr(a), _ptr(p), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"RMSE_{length}", "errors", offset)
|
|
|
|
|
|
def mae(actual: object, predicted: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Mean Absolute Error."""
|
|
length = int(length); offset = int(offset)
|
|
a, idx = _arr(actual); p, _ = _arr(predicted)
|
|
n = len(a); dst = _out(n)
|
|
_check(_lib.qtl_mae(_ptr(a), _ptr(p), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"MAE_{length}", "errors", offset)
|
|
|
|
|
|
def mape(actual: object, predicted: object, length: int = 20,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Mean Absolute Percentage Error."""
|
|
length = int(length); offset = int(offset)
|
|
a, idx = _arr(actual); p, _ = _arr(predicted)
|
|
n = len(a); dst = _out(n)
|
|
_check(_lib.qtl_mape(_ptr(a), _ptr(p), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"MAPE_{length}", "errors", offset)
|
|
'''
|
|
|
|
|
|
# ── filters.py ──
|
|
filters_additions = '''
|
|
|
|
def bessel(close: object, length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Bessel Filter."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bessel(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"BESSEL_{length}", "filters", offset)
|
|
|
|
|
|
def butter2(close: object, length: int = 14, gain: float = 1.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""2nd-order Butterworth."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_butter2(_ptr(src), n, _ptr(dst), length, float(gain)))
|
|
return _wrap(dst, idx, f"BUTTER2_{length}", "filters", offset)
|
|
|
|
|
|
def butter3(close: object, length: int = 14, gain: float = 1.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""3rd-order Butterworth."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_butter3(_ptr(src), n, _ptr(dst), length, float(gain)))
|
|
return _wrap(dst, idx, f"BUTTER3_{length}", "filters", offset)
|
|
|
|
|
|
def cheby1(close: object, length: int = 14, ripple: float = 0.5,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Chebyshev Type I."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cheby1(_ptr(src), n, _ptr(dst), length, float(ripple)))
|
|
return _wrap(dst, idx, f"CHEBY1_{length}", "filters", offset)
|
|
|
|
|
|
def cheby2(close: object, length: int = 14, ripple: float = 0.5,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Chebyshev Type II."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cheby2(_ptr(src), n, _ptr(dst), length, float(ripple)))
|
|
return _wrap(dst, idx, f"CHEBY2_{length}", "filters", offset)
|
|
|
|
|
|
def elliptic(close: object, length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Elliptic (Cauer) Filter."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_elliptic(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"ELLIPTIC_{length}", "filters", offset)
|
|
|
|
|
|
def edcf(close: object, length: int = 14, offset: int = 0, **kwargs) -> object:
|
|
"""Ehlers Distance Coefficient Filter."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_edcf(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"EDCF_{length}", "filters", offset)
|
|
|
|
|
|
def bpf(close: object, length: int = 14, bandwidth: int = 5,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Bandpass Filter."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bpf(_ptr(src), n, _ptr(dst), length, int(bandwidth)))
|
|
return _wrap(dst, idx, f"BPF_{length}", "filters", offset)
|
|
|
|
|
|
def alaguerre(close: object, length: int = 20, order: int = 5,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Adaptive Laguerre Filter."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_alaguerre(_ptr(src), n, _ptr(dst), length, int(order)))
|
|
return _wrap(dst, idx, f"ALAGUERRE_{length}", "filters", offset)
|
|
|
|
|
|
def bilateral(close: object, length: int = 14, sigma_s: float = 0.5,
|
|
sigma_r: float = 1.0, offset: int = 0, **kwargs) -> object:
|
|
"""Bilateral Filter."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_bilateral(_ptr(src), n, _ptr(dst), length, float(sigma_s), float(sigma_r)))
|
|
return _wrap(dst, idx, f"BILATERAL_{length}", "filters", offset)
|
|
|
|
|
|
def baxterking(close: object, length: int = 12, min_period: int = 6,
|
|
max_period: int = 32, offset: int = 0, **kwargs) -> object:
|
|
"""Baxter-King Filter."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_baxterking(_ptr(src), n, _ptr(dst), length, int(min_period), int(max_period)))
|
|
return _wrap(dst, idx, f"BAXTERKING_{length}", "filters", offset)
|
|
|
|
|
|
def cfitz(close: object, length: int = 6, bw_period: int = 32,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Christiano-Fitzgerald Filter."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cfitz(_ptr(src), n, _ptr(dst), length, int(bw_period)))
|
|
return _wrap(dst, idx, f"CFITZ_{length}", "filters", offset)
|
|
'''
|
|
|
|
|
|
# ── cycles.py ──
|
|
cycles_additions = '''
|
|
|
|
def cg(close: object, length: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Center of Gravity."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cg(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"CG_{length}", "cycles", offset)
|
|
|
|
|
|
def dsp(close: object, length: int = 20, offset: int = 0, **kwargs) -> object:
|
|
"""Dominant Cycle Period (DSP)."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dsp(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"DSP_{length}", "cycles", offset)
|
|
|
|
|
|
def ccor(close: object, length: int = 20, alpha: float = 0.07,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Circular Correlation."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_ccor(_ptr(src), n, _ptr(dst), length, float(alpha)))
|
|
return _wrap(dst, idx, f"CCOR_{length}", "cycles", offset)
|
|
|
|
|
|
def ebsw(close: object, hp_length: int = 40, ssf_length: int = 10,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Even Better Sinewave."""
|
|
hp_length = int(hp_length); ssf_length = int(ssf_length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_ebsw(_ptr(src), n, _ptr(dst), hp_length, ssf_length))
|
|
return _wrap(dst, idx, f"EBSW_{hp_length}", "cycles", offset)
|
|
|
|
|
|
def eacp(close: object, min_period: int = 8, max_period: int = 48,
|
|
avg_length: int = 3, enhance: int = 1,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Ehlers Autocorrelation Periodogram."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_eacp(_ptr(src), n, _ptr(dst), int(min_period), int(max_period), int(avg_length), int(enhance)))
|
|
return _wrap(dst, idx, f"EACP_{min_period}_{max_period}", "cycles", offset)
|
|
'''
|
|
|
|
|
|
# ── numerics.py ──
|
|
numerics_additions = '''
|
|
|
|
def change(close: object, length: int = 1, offset: int = 0, **kwargs) -> object:
|
|
"""Price Change."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_change(_ptr(src), n, _ptr(dst), length))
|
|
return _wrap(dst, idx, f"CHANGE_{length}", "numerics", offset)
|
|
|
|
|
|
def exptrans(close: object, offset: int = 0, **kwargs) -> object:
|
|
"""Exponential Transform."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_exptrans(_ptr(src), n, _ptr(dst)))
|
|
return _wrap(dst, idx, "EXPTRANS", "numerics", offset)
|
|
|
|
|
|
def betadist(close: object, length: int = 50, alpha: float = 2.0,
|
|
beta: float = 2.0, offset: int = 0, **kwargs) -> object:
|
|
"""Beta Distribution."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_betadist(_ptr(src), n, _ptr(dst), length, float(alpha), float(beta)))
|
|
return _wrap(dst, idx, f"BETADIST_{length}", "numerics", offset)
|
|
|
|
|
|
def expdist(close: object, length: int = 50, lam: float = 3.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Exponential Distribution."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_expdist(_ptr(src), n, _ptr(dst), length, float(lam)))
|
|
return _wrap(dst, idx, f"EXPDIST_{length}", "numerics", offset)
|
|
|
|
|
|
def binomdist(close: object, length: int = 50, trials: int = 20,
|
|
threshold: int = 10, offset: int = 0, **kwargs) -> object:
|
|
"""Binomial Distribution."""
|
|
length = int(length); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_binomdist(_ptr(src), n, _ptr(dst), length, int(trials), int(threshold)))
|
|
return _wrap(dst, idx, f"BINOMDIST_{length}", "numerics", offset)
|
|
|
|
|
|
def cwt(close: object, scale: float = 10.0, omega: float = 6.0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Continuous Wavelet Transform."""
|
|
offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_cwt(_ptr(src), n, _ptr(dst), float(scale), float(omega)))
|
|
return _wrap(dst, idx, "CWT", "numerics", offset)
|
|
|
|
|
|
def dwt(close: object, length: int = 4, levels: int = 0,
|
|
offset: int = 0, **kwargs) -> object:
|
|
"""Discrete Wavelet Transform."""
|
|
length = int(length); levels = int(levels); offset = int(offset)
|
|
src, idx = _arr(close); n = len(src); dst = _out(n)
|
|
_check(_lib.qtl_dwt(_ptr(src), n, _ptr(dst), length, levels))
|
|
return _wrap(dst, idx, f"DWT_{length}", "numerics", offset)
|
|
'''
|
|
|
|
|
|
# Now apply all additions
|
|
additions = {
|
|
"core.py": (core_additions, ["avgprice", "medprice", "typprice", "midbody"]),
|
|
"momentum.py": (momentum_additions, ["rsi", "roc", "mom", "cmo", "tsi", "apo", "bias", "cfo", "cfb", "asi"]),
|
|
"oscillators.py": (oscillators_additions, ["fisher", "fisher04", "dpo", "trix", "inertia", "rsx", "er", "cti", "reflex", "trendflex", "kri", "psl", "deco", "dosc", "dymoi", "crsi", "bbb", "bbi", "dem", "brar"]),
|
|
"trends_fir.py": (trends_fir_additions, ["sma", "wma", "hma", "trima", "swma", "dwma", "blma", "alma", "lsma", "sgma", "sinema", "hanma", "parzen", "tsf", "conv", "bwma", "crma", "sp15", "tukey_w", "rain", "afirma"]),
|
|
"trends_iir.py": (trends_iir_additions, ["ema", "ema_alpha", "dema", "dema_alpha", "tema", "lema", "hema", "ahrens", "decycler", "dsma", "gdema", "coral", "agc", "ccyc"]),
|
|
"channels.py": (channels_additions, ["bbands", "aberr", "atrbands", "apchannel"]),
|
|
"volatility.py": (volatility_additions, ["tr", "bbw", "bbwn", "bbwp", "stddev", "variance", "etherm", "ccv", "cv", "cvi", "ewma"]),
|
|
"volume.py": (volume_additions, ["obv", "pvt", "pvr", "vf", "nvi", "pvi", "tvi", "pvd", "vwma", "evwma", "efi", "aobv", "mfi", "cmf", "eom", "pvo"]),
|
|
"statistics.py": (statistics_additions, ["zscore", "cma", "entropy", "correlation", "covariance", "cointegration"]),
|
|
"errors.py": (errors_additions, ["mse", "rmse", "mae", "mape"]),
|
|
"filters.py": (filters_additions, ["bessel", "butter2", "butter3", "cheby1", "cheby2", "elliptic", "edcf", "bpf", "alaguerre", "bilateral", "baxterking", "cfitz"]),
|
|
"cycles.py": (cycles_additions, ["cg", "dsp", "ccor", "ebsw", "eacp"]),
|
|
"numerics.py": (numerics_additions, ["change", "exptrans", "betadist", "expdist", "binomdist", "cwt", "dwt"]),
|
|
}
|
|
|
|
total_added = 0
|
|
for filename, (code, funcnames) in additions.items():
|
|
filepath = os.path.join(PKG, filename)
|
|
content = read(filepath)
|
|
|
|
# Check which functions are already defined
|
|
missing = [f for f in funcnames if f"\ndef {f}(" not in content]
|
|
if not missing:
|
|
print(f" {filename}: all {len(funcnames)} functions already present")
|
|
continue
|
|
|
|
# Update __all__ to include new functions
|
|
# Find __all__ closing bracket
|
|
import re
|
|
all_match = re.search(r'__all__\s*=\s*\[([^\]]*)\]', content, re.DOTALL)
|
|
if all_match:
|
|
existing_all = all_match.group(1)
|
|
existing_names = [s.strip().strip('"').strip("'") for s in existing_all.split(",") if s.strip().strip('"').strip("'")]
|
|
new_names = [f for f in funcnames if f not in existing_names]
|
|
if new_names:
|
|
all_entries = existing_names + new_names
|
|
new_all = "__all__ = [\n" + "".join(f' "{n}",\n' for n in all_entries) + "]"
|
|
content = content[:all_match.start()] + new_all + content[all_match.end():]
|
|
|
|
# Append the wrapper code
|
|
content += "\n" + code.strip() + "\n"
|
|
|
|
write(filepath, content)
|
|
total_added += len(missing)
|
|
print(f" {filename}: added {len(missing)} functions: {', '.join(missing)}")
|
|
|
|
print(f"\n Total wrappers added: {total_added}")
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Step 3: Rewrite indicators.py as thin re-export
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
print("\nStep 3: Rewriting indicators.py as re-export module ...")
|
|
|
|
CATEGORY_MODULES = [
|
|
"channels", "core", "cycles", "dynamics", "errors", "filters",
|
|
"momentum", "numerics", "oscillators", "reversals", "statistics",
|
|
"trends_fir", "trends_iir", "volatility", "volume",
|
|
]
|
|
|
|
indicators_content = '''"""High-level indicator wrappers for quantalib.
|
|
|
|
This module re-exports all indicator functions from per-category submodules.
|
|
Each function accepts numpy arrays (or pandas Series / DataFrame) and
|
|
returns the same type.
|
|
|
|
Category submodules:
|
|
quantalib.channels — Bollinger Bands, Keltner, Donchian, etc.
|
|
quantalib.core — Price transforms (avgprice, medprice, etc.)
|
|
quantalib.cycles — Hilbert, Sinewave, CG, DSP, etc.
|
|
quantalib.dynamics — ADX, Ichimoku, Supertrend, etc.
|
|
quantalib.errors — MSE, RMSE, MAE, MAPE, Huber, etc.
|
|
quantalib.filters — Butterworth, Chebyshev, Kalman, etc.
|
|
quantalib.momentum — RSI, MACD, ROC, MOM, etc.
|
|
quantalib.numerics — FFT, sigmoid, slope, distributions, etc.
|
|
quantalib.oscillators — Stochastic, Fisher, Williams %R, etc.
|
|
quantalib.reversals — Pivot points, PSAR, fractals, etc.
|
|
quantalib.statistics — Z-score, correlation, linreg, etc.
|
|
quantalib.trends_fir — SMA, WMA, HMA, ALMA, etc.
|
|
quantalib.trends_iir — EMA, DEMA, TEMA, JMA, KAMA, etc.
|
|
quantalib.volatility — ATR, TR, Bollinger Width, etc.
|
|
quantalib.volume — OBV, VWAP, MFI, CMF, etc.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
'''
|
|
|
|
for mod in CATEGORY_MODULES:
|
|
indicators_content += f"from .{mod} import * # noqa: F401, F403\n"
|
|
|
|
write(os.path.join(PKG, "indicators.py"), indicators_content)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Step 4: Update __init__.py
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
print("\nStep 4: Updating __init__.py ...")
|
|
|
|
init_content = '''"""quantalib — Python wrapper for QuanTAlib NativeAOT exports.
|
|
|
|
Usage::
|
|
|
|
import quantalib as qtl
|
|
|
|
result = qtl.sma(close_array, length=14)
|
|
result = qtl.bbands(close_array, length=20, std=2.0)
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
from ._loader import load_native_library
|
|
from . import indicators
|
|
from .indicators import * # noqa: F401, F403 — re-export all indicator functions
|
|
|
|
# Re-export per-category submodules for direct access
|
|
from . import ( # noqa: F401
|
|
channels,
|
|
core,
|
|
cycles,
|
|
dynamics,
|
|
errors,
|
|
filters,
|
|
momentum,
|
|
numerics,
|
|
oscillators,
|
|
reversals,
|
|
statistics,
|
|
trends_fir,
|
|
trends_iir,
|
|
volatility,
|
|
volume,
|
|
)
|
|
|
|
from ._compat import ALIASES, get_compat
|
|
from ._bridge import (
|
|
QtlError,
|
|
QtlNullPointerError,
|
|
QtlInvalidLengthError,
|
|
QtlInvalidParamError,
|
|
QtlInternalError,
|
|
)
|
|
|
|
__all__ = [
|
|
"load_native_library",
|
|
"indicators",
|
|
"channels",
|
|
"core",
|
|
"cycles",
|
|
"dynamics",
|
|
"errors",
|
|
"filters",
|
|
"momentum",
|
|
"numerics",
|
|
"oscillators",
|
|
"reversals",
|
|
"statistics",
|
|
"trends_fir",
|
|
"trends_iir",
|
|
"volatility",
|
|
"volume",
|
|
"ALIASES",
|
|
"get_compat",
|
|
"QtlError",
|
|
"QtlNullPointerError",
|
|
"QtlInvalidLengthError",
|
|
"QtlInvalidParamError",
|
|
"QtlInternalError",
|
|
]
|
|
|
|
|
|
def _resolve_version() -> str:
|
|
version_file = Path(__file__).resolve().parents[2] / "lib" / "VERSION"
|
|
if version_file.exists():
|
|
version = version_file.read_text(encoding="utf-8").strip()
|
|
if version:
|
|
return version
|
|
return "0.0.0"
|
|
|
|
|
|
__version__ = _resolve_version()
|
|
'''
|
|
|
|
write(os.path.join(PKG, "__init__.py"), init_content)
|
|
|
|
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
# Step 5: Count & verify
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|
print("\nStep 5: Verification counts ...")
|
|
|
|
import re as re2
|
|
|
|
total_funcs = 0
|
|
for mod in CATEGORY_MODULES:
|
|
filepath = os.path.join(PKG, f"{mod}.py")
|
|
content = read(filepath)
|
|
funcs = re2.findall(r'^def (\w+)\(', content, re2.MULTILINE)
|
|
# Exclude private helpers
|
|
public = [f for f in funcs if not f.startswith('_')]
|
|
total_funcs += len(public)
|
|
print(f" {mod:15s}: {len(public):3d} functions")
|
|
|
|
print(f" {'TOTAL':15s}: {total_funcs:3d} functions")
|
|
print("\nDone!")
|