feat: add overlap studies wrappers and align indicator API names

- add TA-Lib bindings and loader registrations for overlap studies:
  TA_ACCBANDS, TA_BBANDS, TA_DEMA, TA_EMA, TA_HT_TRENDLINE, TA_KAMA
- add new public wrappers in overlap_studies.go:
  AccBands, BBands, DEMA, EMA, HT_TRENDLINE, KAMA
- refactor momentum wrapper names to consistent Go-style exports
  (e.g. Aroon/AroonOsc, MACDExt/MACDFix, Stoch/StochF/StochRSI,
  MinusDI/MinusDM, PlusDI/PlusDM, Trix, UltOsc, WillR)
- rename MAType constants to MA_* for clearer namespacing
- update README to reflect the current exported API and overlap coverage
This commit is contained in:
2026-07-24 18:27:36 +09:00
parent 4b07e7c741
commit 89d990ff1b
6 changed files with 350 additions and 63 deletions
+10 -7
View File
@@ -2,7 +2,7 @@
Go wrapper for selected [TA-Lib](https://ta-lib.org/) functions using [`purego`](https://github.com/ebitengine/purego) to dynamically load the native TA-Lib shared library at runtime.
This project currently exposes a small subset of TA-Lib functions:
This project currently exposes a focused subset of TA-Lib functions:
**Cycle Indicators (Hilbert Transform)**
- `HT_DCPERIOD`
@@ -24,11 +24,14 @@ This project currently exposes a small subset of TA-Lib functions:
- Rounding: `Ceil`, `Floor`, `Sqrt`
**Momentum Indicators**
- Directional Movement: `ADX`, `ADXR`, `DX`, `MINUS_DI`, `MINUS_DM`, `PLUS_DI`, `PLUS_DM`
- Oscillators: `APO`, `AROON`, `AROONOSC`, `BOP`, `CCI`, `CMO`, `IMI`, `MFI`, `MOM`, `PPO`, `RSI`, `TRIX`, `WILLR`, `ULTOSC`
- Directional Movement: `ADX`, `ADXR`, `DX`, `MinusDI`, `MinusDM`, `PlusDI`, `PlusDM`
- Oscillators: `APO`, `Aroon`, `AroonOsc`, `BOP`, `CCI`, `CMO`, `IMI`, `MFI`, `MOM`, `PPO`, `RSI`, `Trix`, `WillR`, `UltOsc`
- Rate of Change: `ROC`, `ROCP`, `ROCR`, `ROCR100`
- MACD family: `MACD`, `MACDEXT`, `MACDFIX`
- Stochastic family: `STOCH`, `STOCHF`, `STOCHRSI`
- MACD family: `MACD`, `MACDExt`, `MACDFix`
- Stochastic family: `Stoch`, `StochF`, `StochRSI`
**Overlap Studies**
- `AccBands`, `BBands`, `DEMA`, `EMA`, `HT_TRENDLINE`, `KAMA`
## Requirements
@@ -114,8 +117,8 @@ func main() {
- Indicator functions return `nil` when the underlying TA-Lib call fails.
- 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 (`SMA`, `EMA`, `WMA`, `DEMA`, `TEMA`, `TRIMA`, `KAMA`, `MAMA`, `T3`).
- Functions returning two outputs (e.g. `AROON`, `MACD`, `STOCH`) return multiple slices; all are `nil` on failure.
- 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.
## Project status
+68
View File
@@ -670,4 +670,72 @@ var (
outNBElement *int32,
outReal []float64,
) int32
accbands func(
startIdx int32,
endIdx int32,
inHigh []float64,
inLow []float64,
inClose []float64,
optInTimePeriod int32,
outBegIdx *int32,
outNBElement *int32,
outUpperBand []float64,
outMiddleBand []float64,
outLowerBand []float64,
) int32
bbands func(
startIdx int32,
endIdx int32,
inReal []float64,
optInTimePeriod int32,
optInNbDevUp float64,
optInNbDevDn float64,
optInMAType int32,
outBegIdx *int32,
outNBElement *int32,
outUpperBand []float64,
outMiddleBand []float64,
outLowerBand []float64,
) int32
dema func(
startIdx int32,
endIdx int32,
inReal []float64,
optInTimePeriod int32,
outBegIdx *int32,
outNBElement *int32,
outReal []float64,
) int32
ema func(
startIdx int32,
endIdx int32,
inReal []float64,
optInTimePeriod int32,
outBegIdx *int32,
outNBElement *int32,
outReal []float64,
) int32
ht_trendline func(
startIdx int32,
endIdx int32,
inReal []float64,
outBegIdx *int32,
outNBElement *int32,
outReal []float64,
) int32
kama func(
startIdx int32,
endIdx int32,
inReal []float64,
optInTimePeriod int32,
outBegIdx *int32,
outNBElement *int32,
outReal []float64,
) int32
)
+7
View File
@@ -95,6 +95,13 @@ func Load() (uintptr, error) {
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")
return ptr, nil
}
+50 -47
View File
@@ -107,14 +107,14 @@ func APO(inReal []float64, optInFastPeriod, optInSlowPeriod int, optInMAType MAT
return outReal
}
// AROON - Aroon reports how recently the highest high and lowest low occurred within a rolling window of length optInTimePeriod, as two 0-100 oscillators.
// Aroon - Aroon reports how recently the highest high and lowest low occurred within a rolling window of length optInTimePeriod, as two 0-100 oscillators.
// Indicates trend strength and direction. Up near 100 = a very recent new high (strong uptrend);
// Down near 100 = a very recent new low. Up/Down crossovers signal trend shifts.
//
// Up = 100*(period-(today-highestIdx))/period
// Down = 100*(period-(today-lowestIdx))/period
// where highestIdx/lowestIdx index the highest high / lowest low over the window [today-period .. today].
func AROON(inHigh, inLow []float64, optInTimePeriod int) ([]float64, []float64) {
func Aroon(inHigh, inLow []float64, optInTimePeriod int) ([]float64, []float64) {
var (
startIdx int32
endIdx = int32(len(inHigh) - 1)
@@ -135,14 +135,14 @@ func AROON(inHigh, inLow []float64, optInTimePeriod int) ([]float64, []float64)
outAroonUp,
outAroonDown,
); SUCCESS != taResult(retCode) {
slog.Debug("AROON", "result", retCode)
slog.Debug("Aroon", "result", retCode)
return nil, nil
}
return outAroonUp, outAroonDown
}
// AROONOSC - Aroon Oscillator: AroonUp minus AroonDown over a lookback window.
// AroonOsc - Aroon Oscillator: AroonUp minus AroonDown over a lookback window.
// Measures trend direction and strength on a -100..+100 scale.
// Positive when the high is more recent than the low (up-trend); negative when the low is more recent (down-trend).
//
@@ -151,7 +151,7 @@ func AROON(inHigh, inLow []float64, optInTimePeriod int) ([]float64, []float64)
// AroonDown = factor * (period - (today - lowestIdx))
// AroonOsc = AroonUp - AroonDown = factor * (highestIdx - lowestIdx)
// highestIdx/lowestIdx = bar index of the highest high / lowest low in the last (period+1) bars.
func AROONOSC(inHigh, inLow []float64, optInTimePeriod int) []float64 {
func AroonOsc(inHigh, inLow []float64, optInTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inHigh) - 1)
@@ -170,7 +170,7 @@ func AROONOSC(inHigh, inLow []float64, optInTimePeriod int) []float64 {
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("AROONOSC", "result", retCode)
slog.Debug("AroonOsc", "result", retCode)
return nil
}
@@ -383,7 +383,7 @@ func MACD(inReal []float64, optInFastPeriod, optInSlowPeriod, optInSignalPeriod
return outMACD, outMACDSignal, outMACDHist
}
// MACDEXT - MACD variant where the fast, slow, and signal moving averages each use a user-selectable MA type.
// MACDExt - MACD variant where the fast, slow, and signal moving averages each use a user-selectable MA type.
// Outputs the MACD line, its signal line, and their difference (histogram).
// Hist sign change (MACD crossing its signal line) flags momentum shifts.
//
@@ -394,7 +394,7 @@ func MACD(inReal []float64, optInFastPeriod, optInSlowPeriod, optInSignalPeriod
//
// Note: If the slow period is set smaller than the fast period, the fast and slow periods and their MA types are swapped so the slow moving average is always the longer one.
// A signal period of 1 disables signal-line smoothing for every signal MAType: the signal equals the MACD line and the histogram is zero.
func MACDEXT(
func MACDExt(
inReal []float64,
optInFastPeriod int, optInFastMAType MAType,
optInSlowPeriod int, optInSlowMAType MAType,
@@ -426,14 +426,14 @@ func MACDEXT(
outMACDSignal,
outMACDHist,
); SUCCESS != taResult(retCode) {
slog.Debug("MACDEXT", "result", retCode)
slog.Debug("MACDExt", "result", retCode)
return nil, nil, nil
}
return outMACD, outMACDSignal, outMACDHist
}
// MACDFIX - MACD with the fast/slow EMAs fixed to the classic 12/26 periods (with the classic fixed smoothing factors 0.15 and 0.075), exposing only the signal period.
// MACDFix - MACD with the fast/slow EMAs fixed to the classic 12/26 periods (with the classic fixed smoothing factors 0.15 and 0.075), exposing only the signal period.
// Signal-line crossovers and histogram sign flag momentum shifts.
//
// MACD = EMA_12 - EMA_26 (fixed k: 0.15 for 12, 0.075 for 26)
@@ -442,7 +442,7 @@ func MACDEXT(
//
// Note: A signal period of 1 disables signal-line smoothing: the signal equals the MACD line and the histogram is zero.
// Before 0.6.5 this parameter value produced misaligned output (issues #48/#59).
func MACDFIX(inReal []float64, optInSignalPeriod int) ([]float64, []float64, []float64) {
func MACDFix(inReal []float64, optInSignalPeriod int) ([]float64, []float64, []float64) {
var (
startIdx int32
endIdx = int32(len(inReal) - 1)
@@ -464,7 +464,7 @@ func MACDFIX(inReal []float64, optInSignalPeriod int) ([]float64, []float64, []f
outMACDSignal,
outMACDHist,
); SUCCESS != taResult(retCode) {
slog.Debug("MACDFIX", "result", retCode)
slog.Debug("MACDFix", "result", retCode)
return nil, nil, nil
}
@@ -535,7 +535,7 @@ func MOM(inReal []float64, optInTimePeriod int) []float64 {
return outReal
}
// MINUS_DI - Wilder's Minus Directional Indicator: the Wilder-smoothed downward directional movement (-DM) normalized by smoothed True Range.
// MinusDI - Wilder's Minus Directional Indicator: the Wilder-smoothed downward directional movement (-DM) normalized by smoothed True Range.
// Measures the strength of downward price movement. Higher -DI indicates a stronger downtrend; compared against +DI to gauge directional dominance.
//
// -DM1 = (prevLow - low) if (prevLow-low)>0 and (high-prevHigh)<(prevLow-low), else 0.
@@ -544,7 +544,7 @@ func MOM(inReal []float64, optInTimePeriod int) []float64 {
// If period<=1: -DI1 = -DM1/TR1 (no ×100).
//
// Note: Wilder's original integer rounding is not applied (it was removed as unreliable when values are near 1).
func MINUS_DI(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
func MinusDI(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inClose) - 1)
@@ -564,14 +564,14 @@ func MINUS_DI(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("MINUS_DI", "result", retCode)
slog.Debug("MinusDI", "result", retCode)
return nil
}
return outReal
}
// MINUS_DM - Minus Directional Movement, the downward component of Wilder's directional movement system.
// MinusDM - Minus Directional Movement, the downward component of Wilder's directional movement system.
// Measures Wilder-smoothed downward price motion over the period. Higher -DM indicates stronger downward directional movement.
//
// diffP = high - prevHigh; diffM = prevLow - low
@@ -579,7 +579,7 @@ func MINUS_DI(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
// period<=1: output raw -DM1 per bar.
// period>1: seed = sum of first (period-1) -DM1; then Wilder smooth each bar:
// -DM = prevMinusDM - prevMinusDM/period (+ -DM1 when the bar qualifies)
func MINUS_DM(inHigh, inLow []float64, optInTimePeriod int) []float64 {
func MinusDM(inHigh, inLow []float64, optInTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inLow) - 1)
@@ -598,15 +598,15 @@ func MINUS_DM(inHigh, inLow []float64, optInTimePeriod int) []float64 {
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("MINUS_DM", "result", retCode)
slog.Debug("MinusDM", "result", retCode)
return nil
}
return outReal
}
// PLUS_DI - Plus Directional Indicator: the Wilder-smoothed positive directional movement expressed as a percentage of the true range.
// Measures the strength of upward price movement. Rising +DI signals strengthening upward direction; compared against MINUS_DI to judge trend direction.
// PlusDI - Plus Directional Indicator: the Wilder-smoothed positive directional movement expressed as a percentage of the true range.
// Measures the strength of upward price movement. Rising +DI signals strengthening upward direction; compared against MinusDI to judge trend direction.
//
// +DM1 = (H-Hprev) if (H-Hprev) > 0 and (H-Hprev) > (Lprev-L), else 0.
// TR1 = true range = max(H-L, |H-Cprev|, |L-Cprev|).
@@ -615,7 +615,7 @@ func MINUS_DM(inHigh, inLow []float64, optInTimePeriod int) []float64 {
// When period <= 1: +DI = +DM1 / TR1 (no *100).
//
// Note: Wilder's original integer rounding of intermediate values is not applied (it was unreliable when values are near 1).
func PLUS_DI(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
func PlusDI(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inClose) - 1)
@@ -635,21 +635,21 @@ func PLUS_DI(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("PLUS_DI", "result", retCode)
slog.Debug("PlusDI", "result", retCode)
return nil
}
return outReal
}
// PLUS_DM - Plus Directional Movement: the Wilder-smoothed accumulation of upward directional movement (+DM1).
// A component of the Directional Movement System used to build +DI/DX/ADX.
// PlusDM - Plus Directional Movement: the Wilder-smoothed accumulation of upward directional movement (+DM1).
// A component of the Directional Movement System used to build PlusDI/DX/ADX.
//
// +DM1 = (high - prevHigh) if (high-prevHigh) > 0 and > (prevLow-low), else 0.
// period<=1: output = +DM1 per bar.
// period>1: seed = sum of first (period-1) +DM1; then Wilder smoothing:
// +DM = prevPlusDM - prevPlusDM/period + +DM1(today)
func PLUS_DM(inHigh, inLow []float64, optInTimePeriod int) []float64 {
func PlusDM(inHigh, inLow []float64, optInTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inLow) - 1)
@@ -668,7 +668,7 @@ func PLUS_DM(inHigh, inLow []float64, optInTimePeriod int) []float64 {
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("PLUS_DM", "result", retCode)
slog.Debug("PlusDM", "result", retCode)
return nil
}
@@ -857,7 +857,7 @@ func RSI(inReal []float64, optInTimePeriod int) []float64 {
return outReal
}
// STOCH - Slow Stochastic oscillator: locates the close within the high-low range over a lookback period, then double-smooths it.
// Stoch - Slow Stochastic oscillator: locates the close within the high-low range over a lookback period, then double-smooths it.
// Returns the Slow-%K and Slow-%D lines. SlowK/SlowD > 80 overbought, < 20 oversold; %K crossing %D signals momentum shifts.
//
// FastK = 100*(Close - LL_n)/(HH_n - LL_n), n = FastK_Period (LL/HH = lowest low / highest high over n)
@@ -865,7 +865,7 @@ func RSI(inReal []float64, optInTimePeriod int) []float64 {
// SlowD = MA(SlowK, SlowD_Period, SlowD_MAType)
//
// Note: When the high-low range over the window is zero, the raw stochastic is set to 0 instead of being undefined.
func STOCH(
func Stoch(
inHigh, inLow, inClose []float64,
optInFastKPeriod int,
optInSlowKPeriod int,
@@ -898,21 +898,21 @@ func STOCH(
outSlowK,
outSlowD,
); SUCCESS != taResult(retCode) {
slog.Debug("STOCH", "result", retCode)
slog.Debug("Stoch", "result", retCode)
return nil, nil
}
return outSlowK, outSlowD
}
// STOCHF - Fast Stochastic Oscillator: the raw %K line and its moving-average-smoothed %D line.
// Unlike STOCH (which slows both lines), STOCHF returns the unsmoothed FastK and FastD. Oscillates 0-100; >80 overbought, <20 oversold.
// StochF - Fast Stochastic Oscillator: the raw %K line and its moving-average-smoothed %D line.
// Unlike Stoch (which slows both lines), StochF returns the unsmoothed FastK and FastD. Oscillates 0-100; >80 overbought, <20 oversold.
//
// FastK = 100 * (Close - LowestLow) / (HighestHigh - LowestLow), over the last FastK_Period bars (incl. today)
// FastD = MA(FastK, FastD_Period, FastD_MAType)
//
// Note: When the high-low range over the window is zero, %K is set to 0 instead of being undefined.
func STOCHF(
func StochF(
inHigh, inLow, inClose []float64,
optInFastKPeriod int,
optInFastDPeriod int,
@@ -941,14 +941,14 @@ func STOCHF(
outFastK,
outFastD,
); SUCCESS != taResult(retCode) {
slog.Debug("STOCHF", "result", retCode)
slog.Debug("StochF", "result", retCode)
return nil, nil
}
return outFastK, outFastD
}
// STOCHRSI - Applies the Fast Stochastic (STOCHF) oscillator to an RSI series instead of price,
// StochRSI - Applies the Fast Stochastic (StochF) oscillator to an RSI series instead of price,
// measuring where RSI sits within its recent min/max range.
// Oscillates 0-100; high = RSI near its recent top, low = near its recent bottom.
//
@@ -958,7 +958,7 @@ func STOCHF(
//
// Note: To reproduce the original article's unsmoothed Stochastic RSI, set the RSI period equal to the %K period and read the raw %K output.
// When the RSI's recent range is zero, %K is set to 0 instead of being undefined.
func STOCHRSI(
func StochRSI(
inReal []float64,
optInTimePeriod int,
optInFastKPeriod int,
@@ -987,21 +987,24 @@ func STOCHRSI(
outFastK,
outFastD,
); SUCCESS != taResult(retCode) {
slog.Debug("STOCHRSI", "result", retCode)
slog.Debug("StochRSI", "result", retCode)
return nil, nil
}
return outFastK, outFastD
}
// TRIX - 1-day Rate-Of-Change of a triple-smoothed EMA of the input.
// Trix - 1-day Rate-Of-Change of a triple-smoothed EMA of the input.
// Momentum oscillator that filters out price moves shorter than the chosen period.
// Oscillates around zero; sign, zero-crossings and slope signal momentum direction.
//
// E1 = EMA(inReal, n); E2 = EMA(E1, n); E3 = EMA(E2, n); TRIX = ROC_1(E3) = 100 * (E3_today/E3_yesterday - 1)
// E1 = EMA(inReal, n);
// E2 = EMA(E1, n);
// E3 = EMA(E2, n);
// Trix = ROC_1(E3) = 100 * (E3_today/E3_yesterday - 1)
//
// Note: The final rate-of-change step yields 0 when the previous smoothed value is exactly zero, rather than being undefined.
func TRIX(inReal []float64, optInTimePeriod int) []float64 {
func Trix(inReal []float64, optInTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inReal) - 1)
@@ -1019,23 +1022,23 @@ func TRIX(inReal []float64, optInTimePeriod int) []float64 {
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("TRIX", "result", retCode)
slog.Debug("Trix", "result", retCode)
return nil
}
return outReal
}
// ULTOSC - Ultimate Oscillator: momentum indicator combining buying-pressure/true-range ratios over three time periods into one 0-100 weighted average.
// UltOsc - Ultimate Oscillator: momentum indicator combining buying-pressure/true-range ratios over three time periods into one 0-100 weighted average.
// Blends short-, medium-, and long-term momentum to damp single-period noise. Ranges 0-100; conventionally >70 overbought, <30 oversold.
//
// trueLow = min(low, prevClose); BP = close - trueLow
// TR = max(high-low, |prevClose-high|, |prevClose-low|)
// avg_n = (sum BP over n bars) / (sum TR over n bars)
// ULTOSC = 100 * (4avg_short + 2avg_mid + avg_long) / 7
// UltOsc = 100 * (4avg_short + 2avg_mid + avg_long) / 7
//
// Note: The three periods are sorted internally, so the 4/2/1 weighting always applies to the shortest, middle, and longest period regardless of the order in which you pass them.
func ULTOSC(
func UltOsc(
inHigh, inLow, inClose []float64,
optInTimePeriod1, optInTimePeriod2, optInTimePeriod3 int,
) []float64 {
@@ -1060,19 +1063,19 @@ func ULTOSC(
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("ULTOSC", "result", retCode)
slog.Debug("UltOsc", "result", retCode)
return nil
}
return outReal
}
// WILLR - Williams' %R momentum oscillator over a rolling period, bounded in [-100, 0].
// WillR - Williams' %R momentum oscillator over a rolling period, bounded in [-100, 0].
// Measures where the current close sits relative to the high-low range of the last N bars.
// Near 0 = close at period high (overbought); near -100 = close at period low (oversold).
//
// %R = -100 * (highestHigh - close) / (highestHigh - lowestLow) over the trailing optInTimePeriod bars; if highestHigh == lowestLow, output 0.
func WILLR(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
func WillR(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inClose) - 1)
@@ -1092,7 +1095,7 @@ func WILLR(inHigh, inLow, inClose []float64, optInTimePeriod int) []float64 {
&outNBElement,
outReal,
); SUCCESS != taResult(retCode) {
slog.Debug("WILLR", "result", retCode)
slog.Debug("WillR", "result", retCode)
return nil
}
+206
View File
@@ -0,0 +1,206 @@
package talib
import "log/slog"
// AccBands - Acceleration Bands: three overlap lines around price.
// The middle band is an SMA of the close; the upper/lower bands are SMAs of the high/low scaled by an intraday-range factor.
//
// factor = 4*(H-L)/(H+L)
// upperRaw = H*(1+factor), lowerRaw = L*(1-factor)
// Upper = SMA(upperRaw, N), Middle = SMA(Close, N), Lower = SMA(lowerRaw, N)
func AccBands(inHigh, inLow, inClose []float64, inTimePeriod int) ([]float64, []float64, []float64) {
var (
startIdx int32
endIdx = int32(len(inClose) - 1)
outBegIdx int32
outNBElement int32
outRealUpperBand = make([]float64, len(inClose))
outRealMiddleBand = make([]float64, len(inClose))
outRealLowerBand = make([]float64, len(inClose))
)
if retCode := accbands(
startIdx,
endIdx,
inHigh,
inLow,
inClose,
int32(inTimePeriod),
&outBegIdx,
&outNBElement,
outRealUpperBand,
outRealMiddleBand,
outRealLowerBand,
); retCode != 0 {
slog.Debug("AccBands", "result", retCode)
return nil, nil, nil
}
return outRealUpperBand, outRealMiddleBand, outRealLowerBand
}
// BBands - Bollinger Bands: a moving-average middle band with upper and lower bands offset by a multiple of the standard deviation.
// Used to gauge relative price volatility.
//
// middle = MA(inReal, period); sd = stddev(inReal, period);
// upper = middle + nbDevUpsd;
// lower = middle - nbDevDnsd
//
// Note: The standard deviation uses the population form (dividing by the period), not the sample form.
// The standard deviation is always computed with a simple moving average regardless of the selected MA type.
func BBands(inReal []float64, inTimePeriod int, inNbDevUp, inNbDevDn float64, inMAType MAType) ([]float64, []float64, []float64) {
var (
startIdx int32
endIdx = int32(len(inReal) - 1)
outBegIdx int32
outNBElement int32
outRealUpperBand = make([]float64, len(inReal))
outRealMiddleBand = make([]float64, len(inReal))
outRealLowerBand = make([]float64, len(inReal))
)
if retCode := bbands(
startIdx,
endIdx,
inReal,
int32(inTimePeriod),
inNbDevUp,
inNbDevDn,
int32(inMAType),
&outBegIdx,
&outNBElement,
outRealUpperBand,
outRealMiddleBand,
outRealLowerBand,
); retCode != 0 {
slog.Debug("BBands", "result", retCode)
return nil, nil, nil
}
return outRealUpperBand, outRealMiddleBand, outRealLowerBand
}
// DEMA - Double Exponential Moving Average: an EMA combined with an EMA-of-EMA to reduce lag versus a plain EMA.
//
// EMA1 = EMA(inReal, period); EMA2 = EMA(EMA1, period); DEMA = 2*EMA1 - EMA2
//
// Note: A period of 1 performs no smoothing: the output is a copy of the input. Allowed since 0.6.5 (issues #48/#59).
func DEMA(inReal []float64, inTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inReal) - 1)
outBegIdx int32
outNBElement int32
outReal = make([]float64, len(inReal))
)
if retCode := dema(
startIdx,
endIdx,
inReal,
int32(inTimePeriod),
&outBegIdx,
&outNBElement,
outReal,
); retCode != 0 {
slog.Debug("DEMA", "result", retCode)
return nil
}
return outReal
}
// EMA - Exponential moving average that weights recent prices more heavily via a recursive smoothing factor.
// A core building block seeding or composing many other indicators. Reacts faster than SMA; price above/below EMA suggests up/down trend.
//
// k = 2 / (period + 1);
// EMA_t = (price_t - EMA_{t-1}) * k + EMA_{t-1}.
// Seed: EMA = SMA of first period bars.
//
// Note: A period of 1 performs no smoothing: the output is a copy of the input. Allowed since 0.6.5 (issues #48/#59).
func EMA(inReal []float64, inTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inReal) - 1)
outBegIdx int32
outNBElement int32
outReal = make([]float64, len(inReal))
)
if retCode := ema(
startIdx,
endIdx,
inReal,
int32(inTimePeriod),
&outBegIdx,
&outNBElement,
outReal,
); retCode != 0 {
slog.Debug("EMA", "result", retCode)
return nil
}
return outReal
}
// HT_TRENDLINE - Ehlers' Hilbert Transform Instantaneous Trendline:
// a smoothed, low-lag overlay whose averaging window adapts to the dominant cycle period measured via Hilbert-transform quadrature (I/Q) analysis of price.
func HT_TRENDLINE(inReal []float64) []float64 {
var (
startIdx int32
endIdx = int32(len(inReal) - 1)
outBegIdx int32
outNBElement int32
outReal = make([]float64, len(inReal))
)
if retCode := ht_trendline(
startIdx,
endIdx,
inReal,
&outBegIdx,
&outNBElement,
outReal,
); retCode != 0 {
slog.Debug("HT_TRENDLINE", "result", retCode)
return nil
}
return outReal
}
// KAMA - Kaufman Adaptive Moving Average: an EMA whose smoothing factor adapts each bar to an efficiency ratio (directional move vs. total volatility).
// Reacts fast in trends and smooths in ranging markets. Flat KAMA = non-trending/ranging market.
// KAMA tracking price closely = efficient trend.
//
// ER = |price[t] - price[t-period]| / sum(|price[i]-price[i-1]|, last period bars)
// SC = (ER*(2/3 - 2/31) + 2/31)^2
// KAMA[t] = KAMA[t-1] + SC*(price[t] - KAMA[t-1])
//
// Note: A period of 1 performs no smoothing: the output is a copy of the input, consistent with MA(period=1) for every MAType.
// (The natural KAMA math at period 1 would degenerate to a fixed-alpha EMA because the efficiency ratio is always 1, so the copy is made explicit.)
// Allowed since 0.6.5.
func KAMA(inReal []float64, inTimePeriod int) []float64 {
var (
startIdx int32
endIdx = int32(len(inReal) - 1)
outBegIdx int32
outNBElement int32
outReal = make([]float64, len(inReal))
)
if retCode := kama(
startIdx,
endIdx,
inReal,
int32(inTimePeriod),
&outBegIdx,
&outNBElement,
outReal,
); retCode != 0 {
slog.Debug("KAMA", "result", retCode)
return nil
}
return outReal
}
+9 -9
View File
@@ -3,13 +3,13 @@ package talib
type MAType int32
const (
SMA MAType = 0 // Simple Moving Average
EMA MAType = 1 // Exponential Moving Average
WMA MAType = 2 // Weighted Moving Average
DEMA MAType = 3 // Double Exponential Moving Average
TEMA MAType = 4 // Triple Exponential Moving Average
TRIMA MAType = 5 // Triangular Moving Average
KAMA MAType = 6 // Kaufman Adaptive Moving Average
MAMA MAType = 7 // MESA Adaptive Moving Average
T3 MAType = 8 // Triple Exponential Moving Average (T3)
MA_SMA MAType = 0 // Simple Moving Average
MA_EMA MAType = 1 // Exponential Moving Average
MA_WMA MAType = 2 // Weighted Moving Average
MA_DEMA MAType = 3 // Double Exponential Moving Average
MA_TEMA MAType = 4 // Triple Exponential Moving Average
MA_TRIMA MAType = 5 // Triangular Moving Average
MA_KAMA MAType = 6 // Kaufman Adaptive Moving Average
MA_MAMA MAType = 7 // MESA Adaptive Moving Average
MA_T3 MAType = 8 // Triple Exponential Moving Average (T3)
)