feat(loader): make Load idempotent and expose TA-Lib version API

- guard library initialization with sync.Once to avoid duplicate registrations
- refactor loading logic into internalLoad()
- register TA_GetVersionString and expose Version()
- document Version() usage and API behavior in README
This commit is contained in:
2026-07-28 12:25:24 +09:00
parent fc504d0c01
commit b3ad421c76
2 changed files with 30 additions and 1 deletions
+4 -1
View File
@@ -48,7 +48,7 @@ This package does **not** bundle TA-Lib itself. You must install the native libr
## How library loading works ## How library loading works
Call `talib.Load()` once before using any indicator function. The loader looks for the platform-specific library name: Call `talib.Load()` once before using any indicator function. After loading, you can call `talib.Version()` to read the native TA-Lib version string. The loader looks for the platform-specific library name:
- macOS: `libta-lib.dylib` - macOS: `libta-lib.dylib`
- Linux: `libta-lib.so` - Linux: `libta-lib.so`
@@ -103,6 +103,8 @@ func main() {
log.Fatal(err) log.Fatal(err)
} }
fmt.Println("TA-Lib version:", talib.Version())
var series []float64 var series []float64
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
series = append(series, math.Sin(float64(i)/7)*4.5+math.Cos(float64(i)/19)*1.75) series = append(series, math.Sin(float64(i)/7)*4.5+math.Cos(float64(i)/19)*1.75)
@@ -122,6 +124,7 @@ func main() {
## API notes ## API notes
- Indicator functions return `nil` when the underlying TA-Lib call fails. - Indicator functions return `nil` when the underlying TA-Lib call fails.
- `Version()` returns the TA-Lib version string exposed by `TA_GetVersionString` (call after `Load()`).
- Native TA-Lib functions are exposed with Go-style exported names such as `Add`, `Div`, `Max`, and `Sum`. - Native TA-Lib functions are exposed with Go-style exported names such as `Add`, `Div`, `Max`, and `Sum`.
- Functions accepting a moving-average type use the `MAType` constant (`MA_SMA`, `MA_EMA`, `MA_WMA`, `MA_DEMA`, `MA_TEMA`, `MA_TRIMA`, `MA_KAMA`, `MA_MAMA`, `MA_T3`). - Functions accepting a moving-average type use the `MAType` constant (`MA_SMA`, `MA_EMA`, `MA_WMA`, `MA_DEMA`, `MA_TEMA`, `MA_TRIMA`, `MA_KAMA`, `MA_MAMA`, `MA_T3`).
- Functions returning multiple outputs (e.g. `Aroon`, `MACD`, `Stoch`) return multiple slices; all are `nil` on failure. - Functions returning multiple outputs (e.g. `Aroon`, `MACD`, `Stoch`) return multiple slices; all are `nil` on failure.
+26
View File
@@ -1,16 +1,40 @@
package talib package talib
import "C"
import ( import (
"fmt" "fmt"
"log/slog" "log/slog"
"os" "os"
"path/filepath" "path/filepath"
"runtime" "runtime"
"sync"
"github.com/ebitengine/purego" "github.com/ebitengine/purego"
) )
var (
internalVersion func() string
once sync.Once
)
func Version() string {
return internalVersion()
}
func Load() (uintptr, error) { func Load() (uintptr, error) {
var (
ptr uintptr
err error
)
once.Do(func() {
ptr, err = internalLoad()
})
return ptr, err
}
func internalLoad() (uintptr, error) {
var ( var (
path string path string
ptr uintptr ptr uintptr
@@ -26,6 +50,8 @@ func Load() (uintptr, error) {
return 0, err return 0, err
} }
purego.RegisterLibFunc(&internalVersion, ptr, "TA_GetVersionString")
// Register the functions we need from the TA-Lib library // Register the functions we need from the TA-Lib library
purego.RegisterLibFunc(&ht_dcperiod, ptr, "TA_HT_DCPERIOD") purego.RegisterLibFunc(&ht_dcperiod, ptr, "TA_HT_DCPERIOD")
purego.RegisterLibFunc(&ht_dcphase, ptr, "TA_HT_DCPHASE") purego.RegisterLibFunc(&ht_dcphase, ptr, "TA_HT_DCPHASE")