Repository navigation
Released 2026-10-10. Full details in CHANGELOG.md.
Install or pin this line with go get github.com/Bitvested/ta.go@v0.21.0; ta.Version reports 2.1.0.
⚠️ Read this before upgradingFour functions return different numbers, and three of them a different number of rows. Each was verified against ta.js, the reference these ports are built from, and each fix has a test that fails against the old code — but nothing raises, so an existing pipeline will consume the new values silently.
function what changed HalfTrendrow count: n - atrlen→n. It also produced zero trend changes on real data before this release.Alligator,Gatorrow count: n - jl - js + 2→n, oldest-first and aligned to the input bars.Kamarow count n - l1→n - l1 + 1, and every value — the smoothing constant had lost its slow term.Hullvalues: the half-length and the final smoothing window were truncated instead of rounded, so the output differed from ta.js at every odd length and wherever sqrtrounds up (8, 14, …).ZigZagvalues: three bookkeeping defects — legs were reset from ±Inf, the running maximum tracked the low, and a low pivot stored the high.
Er,ArandKellyare not in that list: their values are unchanged. What changed is that a one-sided series no longer depends onmath.Pow(1, +Inf)happening to be 1.
Added
Occ— the Open Close Cross, following JustUncleL's Pine (source), requested in Bitvested/ta.py#4. A moving average of open and of close; the direction is whichever is on top and a flip is the cross. Input rows are[open, close]; output rows are[close basis, open basis, direction], aligned to the input bars, NaN until both bases exist.delayis the Pine'sdelayOffset.basisTypeacceptsSMA,EMA,DEMA,TEMA,WMA,SMMA,HullMAandTMA; the other four the Pine offers are omitted rather than approximated (LSMA needs an offset this package'sLsmadoes not take, VWMA needs volume in the row, ALMA and SSMA are not implemented). An unrecognisedbasisTypereturns nil.
Fixed
Fixed
-
AlligatorandGatornow align to the input bars. Both returned
their rows newest-first and truncated ton - jl - js + 2rows, so
the output could not be lined up with the input series at all, and
each line was displaced byshift - 1bars instead ofshift.
Gator's upper histogram also plottedjaw - teethinstead of
|jaw - teeth|, giving the top histogram the wrong sign. Both now
emit one row per input bar, with each line displaced right by its own
shift, matching TradingView'splot(..., offset=shift), and NaN until
that line's first bar (jaw 20, teeth 12, lips 7 with the defaults).
Gatoris now derived fromAlligator's displaced lines, and
js=ts=ls=0reproduces TradingView's Gator Oscillator, which does not
displace its lines. Mirrors the same fix in ta.py and ta.js. -
Kamanow computes Kaufman's adaptive average correctly. Four bugs,
all inherited from the ta.js original: the smoothing constant dropped
its slow term (- 2/(l3+1) + 2/(l3+1)cancelled, leavingER * fast);
the volatility window summedl1-1one-bar changes instead ofl1,
which let the efficiency ratio exceed 1 and divided by zero on flat
input; the seed was the SMA of the last window rather than the first,
so the opening value was computed from data at the end of the series;
and the loop started one bar late, emittingn - l1values instead of
n - l1 + 1.The recursion now matches tulind, the reference the benchmarks compare
against: bit-identical on short, flat, trending and gapping series, max
Δ 1.4e-14 on a 100k random walk. Carrying the volatility sum across
bars instead of re-summing it per bar also makes it ~2.5× faster.
Fixes the same defect as Bitvested/ta.js#22,
mirrored in ta.py. -
HalfTrendno longer sits on one line forever. Reported against ta.py
as #7. The port read the
SMA at the start of its window — roughlyatrlenbars old — instead
of at the current bar, so both flip conditions compared stale values and
never fired: on 4901 bars of 5-minute data it produced zero trend
changes. The extremes behindmaxlow/minhighalso came from the ATR
window rather thanamplitudebars, the down-flip comparedclosewith
<where the Pine uses>, and the windowdata[i-atrlen:i]excluded
the current bar, leaving every value a bar stale.The rewrite follows everget's Pine
line by line. Its ATR uses Pine's own seeding (Wilder's RMA seeded with
the mean of the firstatrlentrue ranges, which is not whatAtr
does). Verified against a transcription of the Pine: exact agreement,
160 flips where there were none, across the three ports. -
Erno longer leaves a one-sided series to an exponentiation edge case.
It took the geometric mean of both sides regardless of how many
observations each had, so a series with no losses relied on
math.Pow(1, +Inf)happening to return 1 — which is not what the other
ports did with the same input: ta.js returned NaN (1 ** Infinityis
NaN in JS) and ta.py raisedZeroDivisionError. An empty side carries
weight zero, so its mean is never taken and it contributes nothing; all
three now state that explicitly and return identical numbers.Erand
theArandKellybuilt on it return 0.0274, and a Kelly fraction of
1, for an all-winning series, and -1.0276 for an all-losing one. Mixed
series are unchanged to the last bit. Mirrors the same fix in ta.js and
ta.py. -
ZigZag's pivot bookkeeping matched neither ta.js nor its own documentation.
Three defects: the leg reset seeded the running extreme with ±Inf instead of
the pivot just recorded, so the next retracement was measured from nothing;
the running maximum tracked the low rather than the high; and a low pivot
stored the high. On a 300-bar series it disagreed with ta.js in 174 of 298
values; it now matches exactly (max Δ 1.4e-14). The existing fixture used a 25%
retracement, where the defects cancel out, which is why they survived — a 5%
case now pins them. -
Hulltruncated where the reference rounds. Both the half-length and the final
smoothing window came fromint(), so the output disagreed with ta.js at every
odd length (half-length) and whereversqrtrounds up — length 8 has sqrt 2.83,
rounded to 3 by the reference and floored to 2 here, which also shifted the
output onto a different bar grid. Both now usemath.Round, and a sweep of
lengths 2-20 matches ta.js exactly. Found while checkingOcc'sHullMAbasis,
which inherits it.
Changed — BREAKING for HalfTrend consumers
HalfTrendreturns one row per input bar instead ofn - atrlen, so
rowicovers bari. The ATR channel is NaN until the ATR window is
full (baratrlen - 1); the trend line itself is defined from bar 0.
Callers that index-shifted the old output to align it with their data no
longer need to.