Files
talib/loader.go
T
beejay 5dcbd4a1cf feat(pattern_recognitions): add 25 remaining Cdl* candlestick pattern wrappers
Complete the TA-Lib candlestick pattern recognition coverage by adding the second
half of the Cdl* function family.

New functions in pattern_recognitions.go (all return []int32, OHLC inputs):
  CdlLadderBottom, CdlLongLeggedDoji, CdlLongLine, CdlMarubozu,
  CdlMatchingLow, CdlMatHold(penetration), CdlMorningDojiStar(penetration),
  CdlMorningStar(penetration), CdlOnNeck, CdlPiercing, CdlRickshawMan,
  CdlRiseFall3Methods, CdlSeparatingLines, CdlShootingStar, CdlShortLine,
  CdlSpinningTop, CdlStalledPattern, CdlStickSandwich, CdlTakuri,
  CdlTasukiGap, CdlThrusting, CdlTristar, CdlUnique3River,
  CdlUpsideGap2Crows, CdlXSideGap3Methods

Supporting changes:
- functions.go: add 25 C function pointer declarations (TA_CDL* signatures)
- loader.go: register all 25 new symbols via purego.RegisterLibFunc in Load()
- cli/main.go: extend smoke harness to exercise all new wrappers
- README.md: document all new patterns in the Pattern Recognition section
2026-07-29 16:24:47 +09:00

283 lines
11 KiB
Go

package talib
import "C"
import (
"fmt"
"log/slog"
"os"
"path/filepath"
"runtime"
"sync"
"github.com/ebitengine/purego"
)
var (
internalVersion func() string
once sync.Once
)
func Version() string {
return internalVersion()
}
func Load() (uintptr, error) {
var (
ptr uintptr
err error
)
once.Do(func() {
ptr, err = internalLoad()
})
return ptr, err
}
func internalLoad() (uintptr, error) {
var (
path string
ptr uintptr
err error
)
if path, err = getExpectedLibraryPath(); err != nil {
return 0, err
}
slog.Debug("Loading TA-Lib library", "path", path)
if ptr, err = purego.Dlopen(path, purego.RTLD_NOW|purego.RTLD_GLOBAL); err != nil {
return 0, err
}
purego.RegisterLibFunc(&internalVersion, ptr, "TA_GetVersionString")
// Register the functions we need from the TA-Lib library
purego.RegisterLibFunc(&ht_dcperiod, ptr, "TA_HT_DCPERIOD")
purego.RegisterLibFunc(&ht_dcphase, ptr, "TA_HT_DCPHASE")
purego.RegisterLibFunc(&ht_phasor, ptr, "TA_HT_PHASOR")
purego.RegisterLibFunc(&ht_sine, ptr, "TA_HT_SINE")
purego.RegisterLibFunc(&ht_trendmode, ptr, "TA_HT_TRENDMODE")
purego.RegisterLibFunc(&add, ptr, "TA_ADD")
purego.RegisterLibFunc(&div, ptr, "TA_DIV")
purego.RegisterLibFunc(&max, ptr, "TA_MAX")
purego.RegisterLibFunc(&maxIndex, ptr, "TA_MAXINDEX")
purego.RegisterLibFunc(&min, ptr, "TA_MIN")
purego.RegisterLibFunc(&minIndex, ptr, "TA_MININDEX")
purego.RegisterLibFunc(&minMax, ptr, "TA_MINMAX")
purego.RegisterLibFunc(&minMaxIndex, ptr, "TA_MINMAXINDEX")
purego.RegisterLibFunc(&mult, ptr, "TA_MULT")
purego.RegisterLibFunc(&sub, ptr, "TA_SUB")
purego.RegisterLibFunc(&sum, ptr, "TA_SUM")
purego.RegisterLibFunc(&cos, ptr, "TA_COS")
purego.RegisterLibFunc(&acos, ptr, "TA_ACOS")
purego.RegisterLibFunc(&cosh, ptr, "TA_COSH")
purego.RegisterLibFunc(&sin, ptr, "TA_SIN")
purego.RegisterLibFunc(&asin, ptr, "TA_ASIN")
purego.RegisterLibFunc(&sinh, ptr, "TA_SINH")
purego.RegisterLibFunc(&tan, ptr, "TA_TAN")
purego.RegisterLibFunc(&atan, ptr, "TA_ATAN")
purego.RegisterLibFunc(&tanh, ptr, "TA_TANH")
purego.RegisterLibFunc(&ceil, ptr, "TA_CEIL")
purego.RegisterLibFunc(&floor, ptr, "TA_FLOOR")
purego.RegisterLibFunc(&sqrt, ptr, "TA_SQRT")
purego.RegisterLibFunc(&exp, ptr, "TA_EXP")
purego.RegisterLibFunc(&ln, ptr, "TA_LN")
purego.RegisterLibFunc(&log10, ptr, "TA_LOG10")
purego.RegisterLibFunc(&adx, ptr, "TA_ADX")
purego.RegisterLibFunc(&adxr, ptr, "TA_ADXR")
purego.RegisterLibFunc(&apo, ptr, "TA_APO")
purego.RegisterLibFunc(&aroon, ptr, "TA_AROON")
purego.RegisterLibFunc(&aroonosc, ptr, "TA_AROONOSC")
purego.RegisterLibFunc(&bop, ptr, "TA_BOP")
purego.RegisterLibFunc(&cci, ptr, "TA_CCI")
purego.RegisterLibFunc(&cmo, ptr, "TA_CMO")
purego.RegisterLibFunc(&cmou, ptr, "TA_CMOU")
purego.RegisterLibFunc(&dx, ptr, "TA_DX")
purego.RegisterLibFunc(&imi, ptr, "TA_IMI")
purego.RegisterLibFunc(&macd, ptr, "TA_MACD")
purego.RegisterLibFunc(&macdext, ptr, "TA_MACDEXT")
purego.RegisterLibFunc(&macdfix, ptr, "TA_MACDFIX")
purego.RegisterLibFunc(&mfi, ptr, "TA_MFI")
purego.RegisterLibFunc(&mom, ptr, "TA_MOM")
purego.RegisterLibFunc(&minus_di, ptr, "TA_MINUS_DI")
purego.RegisterLibFunc(&minus_dm, ptr, "TA_MINUS_DM")
purego.RegisterLibFunc(&plus_di, ptr, "TA_PLUS_DI")
purego.RegisterLibFunc(&plus_dm, ptr, "TA_PLUS_DM")
purego.RegisterLibFunc(&ppo, ptr, "TA_PPO")
purego.RegisterLibFunc(&roc, ptr, "TA_ROC")
purego.RegisterLibFunc(&rocp, ptr, "TA_ROCP")
purego.RegisterLibFunc(&rocr, ptr, "TA_ROCR")
purego.RegisterLibFunc(&rocr100, ptr, "TA_ROCR100")
purego.RegisterLibFunc(&rsi, ptr, "TA_RSI")
purego.RegisterLibFunc(&stoch, ptr, "TA_STOCH")
purego.RegisterLibFunc(&stochf, ptr, "TA_STOCHF")
purego.RegisterLibFunc(&stochrsi, ptr, "TA_STOCHRSI")
purego.RegisterLibFunc(&trix, ptr, "TA_TRIX")
purego.RegisterLibFunc(&ultosc, ptr, "TA_ULTOSC")
purego.RegisterLibFunc(&willr, ptr, "TA_WILLR")
purego.RegisterLibFunc(&accbands, ptr, "TA_ACCBANDS")
purego.RegisterLibFunc(&bbands, ptr, "TA_BBANDS")
purego.RegisterLibFunc(&dema, ptr, "TA_DEMA")
purego.RegisterLibFunc(&ema, ptr, "TA_EMA")
purego.RegisterLibFunc(&ht_trendline, ptr, "TA_HT_TRENDLINE")
purego.RegisterLibFunc(&kama, ptr, "TA_KAMA")
purego.RegisterLibFunc(&ma, ptr, "TA_MA")
purego.RegisterLibFunc(&mama, ptr, "TA_MAMA")
purego.RegisterLibFunc(&mavp, ptr, "TA_MAVP")
purego.RegisterLibFunc(&midpoint, ptr, "TA_MIDPOINT")
purego.RegisterLibFunc(&midprice, ptr, "TA_MIDPRICE")
purego.RegisterLibFunc(&sar, ptr, "TA_SAR")
purego.RegisterLibFunc(&sarext, ptr, "TA_SAREXT")
purego.RegisterLibFunc(&sma, ptr, "TA_SMA")
purego.RegisterLibFunc(&t3, ptr, "TA_T3")
purego.RegisterLibFunc(&tema, ptr, "TA_TEMA")
purego.RegisterLibFunc(&trima, ptr, "TA_TRIMA")
purego.RegisterLibFunc(&wma, ptr, "TA_WMA")
purego.RegisterLibFunc(&avgdev, ptr, "TA_AVGDEV")
purego.RegisterLibFunc(&avgprice, ptr, "TA_AVGPRICE")
purego.RegisterLibFunc(&medprice, ptr, "TA_MEDPRICE")
purego.RegisterLibFunc(&typprice, ptr, "TA_TYPPRICE")
purego.RegisterLibFunc(&wclprice, ptr, "TA_WCLPRICE")
purego.RegisterLibFunc(&beta, ptr, "TA_BETA")
purego.RegisterLibFunc(&correl, ptr, "TA_CORREL")
purego.RegisterLibFunc(&linearreg, ptr, "TA_LINEARREG")
purego.RegisterLibFunc(&linearreg_angle, ptr, "TA_LINEARREG_ANGLE")
purego.RegisterLibFunc(&linearreg_intercept, ptr, "TA_LINEARREG_INTERCEPT")
purego.RegisterLibFunc(&linearreg_slope, ptr, "TA_LINEARREG_SLOPE")
purego.RegisterLibFunc(&stddev, ptr, "TA_STDDEV")
purego.RegisterLibFunc(&tsf, ptr, "TA_TSF")
purego.RegisterLibFunc(&variance, ptr, "TA_VAR")
purego.RegisterLibFunc(&atr, ptr, "TA_ATR")
purego.RegisterLibFunc(&natr, ptr, "TA_NATR")
purego.RegisterLibFunc(&trange, ptr, "TA_TRANGE")
purego.RegisterLibFunc(&ad, ptr, "TA_AD")
purego.RegisterLibFunc(&adosc, ptr, "TA_ADOSC")
purego.RegisterLibFunc(&cmf, ptr, "TA_CMF")
purego.RegisterLibFunc(&nvi, ptr, "TA_NVI")
purego.RegisterLibFunc(&obv, ptr, "TA_OBV")
purego.RegisterLibFunc(&pvi, ptr, "TA_PVI")
purego.RegisterLibFunc(&pvo, ptr, "TA_PVO")
purego.RegisterLibFunc(&cdl2crows, ptr, "TA_CDL2CROWS")
purego.RegisterLibFunc(&cdl3blackcrows, ptr, "TA_CDL3BLACKCROWS")
purego.RegisterLibFunc(&cdl3inside, ptr, "TA_CDL3INSIDE")
purego.RegisterLibFunc(&cdl3linestrike, ptr, "TA_CDL3LINESTRIKE")
purego.RegisterLibFunc(&cdl3outside, ptr, "TA_CDL3OUTSIDE")
purego.RegisterLibFunc(&cdl3starsinsouth, ptr, "TA_CDL3STARSINSOUTH")
purego.RegisterLibFunc(&cdl3whitesoldiers, ptr, "TA_CDL3WHITESOLDIERS")
purego.RegisterLibFunc(&cdlabandonedbaby, ptr, "TA_CDLABANDONEDBABY")
purego.RegisterLibFunc(&cdladvanceblock, ptr, "TA_CDLADVANCEBLOCK")
purego.RegisterLibFunc(&cdlbelthold, ptr, "TA_CDLBELTHOLD")
purego.RegisterLibFunc(&cdlbreakaway, ptr, "TA_CDLBREAKAWAY")
purego.RegisterLibFunc(&cdlclosingmarubozu, ptr, "TA_CDLCLOSINGMARUBOZU")
purego.RegisterLibFunc(&cdlconcealbabyswall, ptr, "TA_CDLCONCEALBABYSWALL")
purego.RegisterLibFunc(&cdlcounterattack, ptr, "TA_CDLCOUNTERATTACK")
purego.RegisterLibFunc(&cdldarkcloudcover, ptr, "TA_CDLDARKCLOUDCOVER")
purego.RegisterLibFunc(&cdldoji, ptr, "TA_CDLDOJI")
purego.RegisterLibFunc(&cdldojistar, ptr, "TA_CDLDOJISTAR")
purego.RegisterLibFunc(&cdldragonflydoji, ptr, "TA_CDLDRAGONFLYDOJI")
purego.RegisterLibFunc(&cdlengulfing, ptr, "TA_CDLENGULFING")
purego.RegisterLibFunc(&cdleveningdojistar, ptr, "TA_CDLEVENINGDOJISTAR")
purego.RegisterLibFunc(&cdleveningstar, ptr, "TA_CDLEVENINGSTAR")
purego.RegisterLibFunc(&cdlgapsidesidewhite, ptr, "TA_CDLGAPSIDESIDEWHITE")
purego.RegisterLibFunc(&cdlgravestonedoji, ptr, "TA_CDLGRAVESTONEDOJI")
purego.RegisterLibFunc(&cdlhammer, ptr, "TA_CDLHAMMER")
purego.RegisterLibFunc(&cdlhangingman, ptr, "TA_CDLHANGINGMAN")
purego.RegisterLibFunc(&cdlharami, ptr, "TA_CDLHARAMI")
purego.RegisterLibFunc(&cdlharamicross, ptr, "TA_CDLHARAMICROSS")
purego.RegisterLibFunc(&cdlhighwave, ptr, "TA_CDLHIGHWAVE")
purego.RegisterLibFunc(&cdlhikkake, ptr, "TA_CDLHIKKAKE")
purego.RegisterLibFunc(&cdlhikkakemod, ptr, "TA_CDLHIKKAKEMOD")
purego.RegisterLibFunc(&cdlhomingpigeon, ptr, "TA_CDLHOMINGPIGEON")
purego.RegisterLibFunc(&cdlidentical3crows, ptr, "TA_CDLIDENTICAL3CROWS")
purego.RegisterLibFunc(&cdlinneck, ptr, "TA_CDLINNECK")
purego.RegisterLibFunc(&cdlinvertedhammer, ptr, "TA_CDLINVERTEDHAMMER")
purego.RegisterLibFunc(&cdlkicking, ptr, "TA_CDLKICKING")
purego.RegisterLibFunc(&cdlkickingbylength, ptr, "TA_CDLKICKINGBYLENGTH")
purego.RegisterLibFunc(&cdlladderbottom, ptr, "TA_CDLLADDERBOTTOM")
purego.RegisterLibFunc(&cdllongleggeddoji, ptr, "TA_CDLLONGLEGGEDDOJI")
purego.RegisterLibFunc(&cdllongline, ptr, "TA_CDLLONGLINE")
purego.RegisterLibFunc(&cdlmarubozu, ptr, "TA_CDLMARUBOZU")
purego.RegisterLibFunc(&cdlmatchinglow, ptr, "TA_CDLMATCHINGLOW")
purego.RegisterLibFunc(&cdlmathold, ptr, "TA_CDLMATHOLD")
purego.RegisterLibFunc(&cdlmorningdojistar, ptr, "TA_CDLMORNINGDOJISTAR")
purego.RegisterLibFunc(&cdlmorningstar, ptr, "TA_CDLMORNINGSTAR")
purego.RegisterLibFunc(&cdlonneck, ptr, "TA_CDLONNECK")
purego.RegisterLibFunc(&cdlpiercing, ptr, "TA_CDLPIERCING")
purego.RegisterLibFunc(&cdlrickshawman, ptr, "TA_CDLRICKSHAWMAN")
purego.RegisterLibFunc(&cdlrisefall3methods, ptr, "TA_CDLRISEFALL3METHODS")
purego.RegisterLibFunc(&cdlseparatinglines, ptr, "TA_CDLSEPARATINGLINES")
purego.RegisterLibFunc(&cdlshootingstar, ptr, "TA_CDLSHOOTINGSTAR")
purego.RegisterLibFunc(&cdlshortline, ptr, "TA_CDLSHORTLINE")
purego.RegisterLibFunc(&cdlspinningtop, ptr, "TA_CDLSPINNINGTOP")
purego.RegisterLibFunc(&cdlstalledpattern, ptr, "TA_CDLSTALLEDPATTERN")
purego.RegisterLibFunc(&cdlsticksandwich, ptr, "TA_CDLSTICKSANDWICH")
purego.RegisterLibFunc(&cdltakuri, ptr, "TA_CDLTAKURI")
purego.RegisterLibFunc(&cdltasukigap, ptr, "TA_CDLTASUKIGAP")
purego.RegisterLibFunc(&cdlthrusting, ptr, "TA_CDLTHRUSTING")
purego.RegisterLibFunc(&cdltristar, ptr, "TA_CDLTRISTAR")
purego.RegisterLibFunc(&cdlunique3river, ptr, "TA_CDLUNIQUE3RIVER")
purego.RegisterLibFunc(&cdlupsidegap2crows, ptr, "TA_CDLUPSIDEGAP2CROWS")
purego.RegisterLibFunc(&cdlxsidegap3methods, ptr, "TA_CDLXSIDEGAP3METHODS")
return ptr, nil
}
func getExpectedLibraryName() (string, error) {
switch runtime.GOOS {
case "windows":
return "libta-lib.dll", nil
case "darwin":
return "libta-lib.dylib", nil
case "linux":
return "libta-lib.so", nil
default:
return "", fmt.Errorf("unsupported platform: %s", runtime.GOOS)
}
}
func getExpectedLibraryPath() (string, error) {
libName, err := getExpectedLibraryName()
if err != nil {
return "", err
}
isExist := func(path string) bool {
_, err := os.Stat(path)
return err == nil
}
if envpath, ok := os.LookupEnv("TA_LIB_PATH"); ok {
p := filepath.Join(envpath, libName)
if isExist(p) {
return p, nil
}
slog.Debug("TA_LIB_PATH environment variable is set but library not found", "path", p)
}
for _, dir := range []string{
".",
"/usr/local/lib",
"/usr/lib",
} {
p := filepath.Join(dir, libName)
if isExist(p) {
return p, nil
}
}
return "", fmt.Errorf("library not found: %s", libName)
}