2026-07-24 18:27:36 +09:00
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
}
2026-07-27 16:04:46 +09:00
// MA - Generic moving-average dispatcher that forwards the job to a concrete MA implementation selected by optInMAType.
// Single uniform interface over all TA-Lib moving averages.
//
// outReal = MA_of_type(optInMAType)(inReal, optInTimePeriod); default type = SMA
//
// Note: A period of 1 performs no smoothing for every MAType: the output is a copy of the input.
// `TA_MAType_DISABLED` bypasses smoothing explicitly, for any period: the output is a copy of the input with a lookback of 0.
// Every function that takes an MAType parameter accepts it.
func MA ( inReal [] float64 , inTimePeriod int , inMAType MAType ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inReal ))
)
if retCode := ma (
startIdx ,
endIdx ,
inReal ,
int32 ( inTimePeriod ),
int32 ( inMAType ),
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "MA" , "result" , retCode )
return nil
}
return outReal
}
// MAMA - MESA Adaptive Moving Average: an adaptive EMA whose smoothing factor is driven by the dominant-cycle phase rate measured with a Hilbert transform.
// Emits two lines, MAMA and its slower follower FAMA.
// MAMA crossing above FAMA is bullish; crossing below is bearish.
//
// phase = atan(Q1/I1) in degrees; deltaPhase = max(1, prevPhase - phase)
// alpha = max(fastLimit/deltaPhase, slowLimit) if deltaPhase>1 else fastLimit
// MAMA = alpha*price + (1-alpha)*MAMA_prev
// FAMA = (alpha/2)*MAMA + (1-alpha/2)*FAMA_prev
// @param inReal Input data series
// @param inFastLimit Upper bound on the adaptive smoothing factor; default 0.5 (0.01 to 0.99)
// @param inSlowLimit Lower bound on the adaptive smoothing factor; default 0.05 (0.01 to 0.99)
func MAMA ( inReal [] float64 , inFastLimit , inSlowLimit float64 ) ([] float64 , [] float64 ) {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outMAMA = make ([] float64 , len ( inReal ))
outFAMA = make ([] float64 , len ( inReal ))
)
if retCode := mama (
startIdx ,
endIdx ,
inReal ,
inFastLimit ,
inSlowLimit ,
& outBegIdx ,
& outNBElement ,
outMAMA ,
outFAMA ,
); retCode != 0 {
slog . Debug ( "MAMA" , "result" , retCode )
return nil , nil
}
return outMAMA , outFAMA
}
// MAVP - Moving average whose period varies per bar, driven by a companion period series.
// For each bar it computes an MA of the selected type over the (clamped) period given by inPeriods.
//
// p_i = clamp((int)inPeriods[startIdx+i], optInMinPeriod, optInMaxPeriod); outReal[i] = MA(inReal, p_i, optInMAType) at bar startIdx+i
//
// Note: Fractional per-bar periods are truncated to whole numbers before being clamped to the minimum and maximum period.
// Period values of 1 perform no smoothing (the bar's output equals its input); the minimum allowed period is 1 since 0.6.5.
// @param inReal Input data series
// @param inPeriods per-bar desired MA period
// @param inMinPeriod Lower clamp for the per-bar period; default 2 (1-100000)
// @param inMaxPeriod Upper clamp for the per-bar period; default 30 (1-100000)
// @param inMAType Type of moving average to compute; default talib.MA_SMA
func MAVP ( inReal , inPeriods [] float64 , inMinPeriod , inMaxPeriod int , inMAType MAType ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inReal ))
)
if retCode := mavp (
startIdx ,
endIdx ,
inReal ,
inPeriods ,
int32 ( inMinPeriod ),
int32 ( inMaxPeriod ),
int32 ( inMAType ),
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "MAVP" , "result" , retCode )
return nil
}
return outReal
}
// MidPoint - Midpoint over a period: the average of the highest and lowest input values within the lookback window.
// A single-series overlap smoother (use MIDPRICE for separate high/low price bars).
//
// MIDPOINT = (Highest(inReal, period) + Lowest(inReal, period)) / 2
// @param inReal Input data series
// @param inTimePeriod Lookback window length; default 14 (2-100000)
func MidPoint ( inReal [] float64 , inTimePeriod int ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inReal ))
)
if retCode := midpoint (
startIdx ,
endIdx ,
inReal ,
int32 ( inTimePeriod ),
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "MidPoint" , "result" , retCode )
return nil
}
return outReal
}
// MidPrice - Midpoint of the price range over a rolling window: the average of the highest high and lowest low across the last optInTimePeriod bars.
// An overlap-study line plotted on price.
//
// MIDPRICE = (Highest(High, N) + Lowest(Low, N)) / 2, over the N=optInTimePeriod bars ending at each index
// @param inHigh Input high price series
// @param inLow Input low price series
// @param inTimePeriod Lookback window length; default 14 (2-100000)
func MidPrice ( inHigh , inLow [] float64 , inTimePeriod int ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inHigh ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inHigh ))
)
if retCode := midprice (
startIdx ,
endIdx ,
inHigh ,
inLow ,
int32 ( inTimePeriod ),
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "MidPrice" , "result" , retCode )
return nil
}
return outReal
}
// SAR - Wilder's Parabolic SAR (Stop And Reverse): a trailing stop/reverse level that accelerates toward price via an acceleration factor.
// Signals trend direction and trailing exit points.
// SAR below price = uptrend (long);
// SAR above price = downtrend (short).
// Price crossing SAR flips direction.
//
// SAR_next = SAR + af * (EP - SAR)
// EP = extreme point (highest high in long / lowest low in short); af starts at Acceleration, += Acceleration each new EP, capped at Maximum.
// On penetration: reverse, SAR := prior EP, reset af = Acceleration. SAR clamped each bar so it does not penetrate the prior/current bar's range.
// @param inHigh Input high price series
// @param inLow Input low price series
// @param inAcceleration Step added to the acceleration factor on each new extreme point; default 0.02 (>=0)
// @param inMaximum Ceiling on the acceleration factor; default 0.2 (>=0)
func SAR ( inHigh , inLow [] float64 , inAcceleration , inMaximum float64 ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inHigh ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inHigh ))
)
if retCode := sar (
startIdx ,
endIdx ,
inHigh ,
inLow ,
inAcceleration ,
inMaximum ,
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "SAR" , "result" , retCode )
return nil
}
return outReal
}
// SARExt - Extended Parabolic SAR (stop and reverse) giving the caller full control over the initial state and separate acceleration factors for long and short positions.
// Unlike SAR, it returns negative values while short so reversals are distinguishable.
// Sign flip of the output marks a trend reversal (positive=long stop, negative=short stop).
//
// SAR_next = SAR + AF*(EP - SAR), then clamped within the prior and current bar's range.
// On penetration, reverse: set SAR=EP (clamped), reset AF to its Init value, EP=extreme of the new direction.
// Output is +SAR when long, -SAR when short. On reversal an optional offset is applied: long->short SAR*(1+offset), short->long SAR*(1-offset).
// @param inHigh Input high price series
// @param inLow Input low price series
// @param inStartValue Initial SAR/direction: 0 auto, >0 start long at value, <0 start short at |value|; default 0 (any real number)
// @param inOffsetOnReverse Fractional offset applied to the stop on each reversal; default 0 (>=0)
// @param inAccelerationInitLong Initial acceleration factor when long; default 0.02 (>=0)
// @param inAccelerationLong AF increment per new long extreme; default 0.02 (>=0)
// @param inAccelerationMaxLong Cap on the long acceleration factor; default 0.2 (>=0)
// @param inAccelerationInitShort Initial acceleration factor when short; default 0.02 (>=0)
// @param inAccelerationShort AF increment per new short extreme; default 0.02 (>=0)
// @param inAccelerationMaxShort Cap on the short acceleration factor; default 0.2 (>=0)
func SARExt (
inHigh , inLow [] float64 ,
inStartValue , inOffsetOnReverse ,
inAccelerationInitLong , inAccelerationLong , inAccelerationMaxLong ,
inAccelerationInitShort , inAccelerationShort , inAccelerationMaxShort float64 ,
) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inHigh ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inHigh ))
)
if retCode := sarext (
startIdx ,
endIdx ,
inHigh ,
inLow ,
inStartValue ,
inOffsetOnReverse ,
inAccelerationInitLong ,
inAccelerationLong ,
inAccelerationMaxLong ,
inAccelerationInitShort ,
inAccelerationShort ,
inAccelerationMaxShort ,
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "SARExt" , "result" , retCode )
return nil
}
return outReal
}
// SMA - Simple Moving Average: the unweighted arithmetic mean of the last N input values. Used to smooth a series.
//
// SMA_t = (1/N) * sum_{i=t-N+1}^{t} inReal_i
//
// 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 SMA ( inReal [] float64 , inTimePeriod int ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inReal ))
)
if retCode := sma (
startIdx ,
endIdx ,
inReal ,
int32 ( inTimePeriod ),
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "SMA" , "result" , retCode )
return nil
}
return outReal
}
// T3 - Tillson's T3: a low-lag moving average built from six chained EMAs, combined via volume-factor-weighted coefficients.
// Not the same as EMA3, despite both being called "triple EMA".
//
// k = 2/(period+1); e1=EMA(x), e2=EMA(e1), ... e6=EMA(e5) (six chained EMAs).
// v = vFactor: c1 = -v^3; c2 = 3(v^2 - c1); c3 = -6v^2 - 3(v - c1); c4 = 1 + 3v - c1 + 3v^2.
// T3 = c1e6 + c2e5 + c3e4 + c4e3
//
// Note: A period of 1 performs no smoothing: the output is a copy of the input. Allowed since 0.6.5 (issues #48/#59).
// @param inReal Input data series
// @param inTimePeriod EMA period for each of the six stages; default 5 (2-100000)
// @param inVFactor Volume factor weighting the coefficients (0 = plain triple EMA, higher = more DEMA-like sharpening); default 0.7 (0-1)
func T3 ( inReal [] float64 , inTimePeriod int , inVFactor float64 ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inReal ))
)
if retCode := t3 (
startIdx ,
endIdx ,
inReal ,
int32 ( inTimePeriod ),
inVFactor ,
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "T3" , "result" , retCode )
return nil
}
return outReal
}
// TEMA - Triple Exponential Moving Average: a smoothed price overlay built from three successively-applied EMAs to reduce lag versus a plain EMA.
// Distinct from EMA3, also called "triple EMA" in the literature.
//
// EMA1=EMA(t,period); EMA2=EMA(EMA1,period); EMA3=EMA(EMA2,period); TEMA = 3EMA1 - 3EMA2 + EMA3
//
// 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 TEMA ( inReal [] float64 , inTimePeriod int ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inReal ))
)
if retCode := tema (
startIdx ,
endIdx ,
inReal ,
int32 ( inTimePeriod ),
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "TEMA" , "result" , retCode )
return nil
}
return outReal
}
// TRIMA - Triangular Moving Average: a double-smoothed moving average that weights prices toward the middle of the window most heavily.
// Equivalent to an SMA of an SMA, computed here via an incremental triangular-weighted running numerator.
//
// Weights rise then fall (4-period: (1a+2b+2c+1d)/6; 5-period: (1a+2b+3c+2d+1e)/9).
// With n = period>>1: odd divides by (n+1)^2, even by n(n+1).
// Equivalent to odd: SMA(SMA(x,(period+1)/2),(period+1)/2); even: SMA(SMA(x,period/2),period/2+1).
//
// Note: Follows the generally accepted (Metastock) definition rather than the TradeStation variant.
// A period of 1 performs no smoothing: the output is a copy of the input. Allowed since 0.6.5 (issues #48/#59).
func TRIMA ( inReal [] float64 , inTimePeriod int ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inReal ))
)
if retCode := trima (
startIdx ,
endIdx ,
inReal ,
int32 ( inTimePeriod ),
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "TRIMA" , "result" , retCode )
return nil
}
return outReal
}
// WMA - Linearly weighted moving average: each of the last N prices is weighted by its position,
// oldest getting weight 1 and newest weight N. Smooths price while emphasizing recent bars.
//
// WMA = ( sum_{k=1..N} k * P_k ) / (N(N+1)/2), where P_N is the most recent bar
//
// 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 WMA ( inReal [] float64 , inTimePeriod int ) [] float64 {
var (
startIdx int32
endIdx = int32 ( len ( inReal ) - 1 )
outBegIdx int32
outNBElement int32
outReal = make ([] float64 , len ( inReal ))
)
if retCode := wma (
startIdx ,
endIdx ,
inReal ,
int32 ( inTimePeriod ),
& outBegIdx ,
& outNBElement ,
outReal ,
); retCode != 0 {
slog . Debug ( "WMA" , "result" , retCode )
return nil
}
return outReal
}