Moving Averages Supported by BanTA: A Complete Guide to 12 MA Types
BanTA supports 12 distinct moving average algorithms—including SMA, EMA, VWMA, WMA, HMA, KAMA, ALMA, and Wilder’s RMA—implemented as both slice-based functions and stateful Series methods for Go and Python.
BanTA is the technical analysis engine inside the banbox/banta repository, designed for high-performance financial calculations. The library implements moving averages supported by BanTA through a dual API architecture: pure functions for batch processing in tav/indicators.go and object-oriented methods for streaming data in sta_inds.go. All implementations are NaN-tolerant, batch-optimized, and designed to handle real-world market data gaps.
Overview of BanTA Moving Average Types
BanTA organizes its moving average implementations across two primary APIs to optimize for different computational contexts. The slice-based functions in tav/indicators.go operate on []float64 slices and compute entire series in single passes. The Series methods in sta_inds.go provide stateful calculations on the *Series type, caching results and maintaining minimal auxiliary state for incremental updates.
Core Design Principles
All moving averages supported by BanTA share three critical characteristics:
- NaN-tolerant: Any
math.NaN()input produces NaN output at that index and resets internal state, handling market data gaps without manual preprocessing. - Batch-optimized: Slice implementations compute entire arrays in single passes without per-point allocations.
- Series-aware: Stateful methods reuse cached results via
obj.To(...)and maintain running calculations (cumulative sums, sliding windows, or exponential smoothing factors) for real-time data feeds.
The 12 Moving Average Algorithms in BanTA
Simple Moving Average (SMA)
The SMA calculates the arithmetic mean of the last n values. In tav/indicators.go, the slice implementation func SMA(data []float64, period int) []float64 processes the entire array in a single pass. For streaming applications, sta_inds.go provides func SMA(obj *Series, period int) *Series, which maintains a sliding window sum to incrementally update averages without recalculating from scratch.
Volume-Weighted Moving Average (VWMA)
The VWMA weights price by traded volume, giving high-volume bars greater influence. The slice function func VWMA(price, volume []float64, period int) []float64 in tav/indicators.go requires parallel price and volume slices. The Series method in sta_inds.go uses a moreVWMA struct to cache volume data and compute func VWMA(obj *Series, volume *Series, period int) *Series.
Exponential Moving Average (EMA and EMABy)
The EMA applies exponential smoothing with factor α = 2/(n+1), weighting recent data more heavily. The basic implementation func EMA(data []float64, period int) []float64 initializes using the SMA of the first period. For custom initialization, EMABy provides func EMABy(data []float64, period int, initType int) []float64, allowing the first value to be either the SMA or the first valid price. Both are available as Series methods func EMA(obj *Series, period int) *Series and func EMABy(obj *Series, period int, initType int) *Series in sta_inds.go.
Relative Moving Average (RMA and RMABy)
RMA implements Wilder’s smoothing with α = 1/n, commonly used in RSI calculations. The slice function func RMA(data []float64, period int) []float64 and its variant RMABy func RMABy(data []float64, period int, initType int, initVal float64) []float64 allow specifying an explicit initial value. The Series implementations func RMA(obj *Series, period int) *Series and func RMABy(obj *Series, period int, initType int, initVal float64) *Series maintain the running Wilder’s smoothing state for streaming data.
Weighted Moving Average (WMA)
The WMA applies linear weights (1, 2, … , n) where the newest observation receives the highest weight. Implemented as func WMA(data []float64, period int) []float64 for slices and func WMA(obj *Series, period int) *Series for Series objects.
Hull Moving Average (HMA)
The HMA reduces lag by combining two WMAs and applying a final WMA to their difference, using period √n. The implementation func HMA(data []float64, period int) []float64 handles the nested WMA calculations internally. The Series method func HMA(obj *Series, period int) *Series provides the same low-lag smoothing for streaming applications.
Kaufman Adaptive Moving Average (KAMA)
KAMA adjusts smoothing based on the market “efficiency ratio,” becoming more responsive during strong trends and slower during noisy, sideways markets. The core logic resides in func KAMABy(data []float64, period int, fast, slow float64) []float64, with func KAMA(data []float64, period int) []float64 serving as a convenience wrapper using default fast/slow parameters. The Series API exposes func KAMA(obj *Series, period int) *Series.
Arnaud Legoux Moving Average (ALMA)
The ALMA uses Gaussian-shaped weights controlled by σ (smoothness) and distOff (offset), offering superior smoothness with minimal lag compared to standard moving averages. Implemented as func ALMA(data []float64, period int, sigma, distOff float64) []float64 for slices and func ALMA(obj *Series, period int, sigma, distOff float64) *Series for Series objects.
Implementation Architecture
BanTA organizes its moving average implementations across three key files to optimize for different use cases.
Batch Processing with tav/indicators.go
The tav/indicators.go file contains pure functions operating on []float64 slices. These implementations are batch-optimized, computing entire series in single passes without per-point allocations. All functions are NaN-tolerant: encountering math.NaN() resets internal state and propagates NaN to the output.
Streaming Data with sta_inds.go
For real-time applications, sta_inds.go provides methods on the *Series type. These implementations cache results via obj.To(...) and maintain minimal auxiliary state—such as cumulative sums for SMA or exponential smoothing factors for EMA—to support incremental calculations in streaming scenarios.
Python Bindings
The python/tav/index.go file exposes the same moving average algorithms to Python via gopy, allowing data scientists to leverage BanTA's performance while working in Python ecosystems.
Practical Code Examples
Calculating SMA and EMA on Historical Data
package main
import (
"fmt"
"github.com/banbox/banta/tav"
)
func main() {
close := []float64{101, 102, 103, 104, 105, 106, 107, 108, 109, 110,
111, 112, 113, 114, 115, 116, 117, 118, 119, 120}
// Simple Moving Average
sma20 := tav.SMA(close, 20)
fmt.Printf("SMA(20): %v\n", sma20)
// Exponential Moving Average
ema20 := tav.EMA(close, 20)
fmt.Printf("EMA(20): %v\n", ema20)
}
Volume-Weighted Analysis with VWMA
price := []float64{10, 10.2, 10.4, 10.1, 10.3, 10.5, 10.6, 10.7, 10.8, 11.0,
11.2, 11.1}
volume := []float64{1000, 1500, 1200, 1300, 1100, 1400, 1600, 1700, 1800, 1900,
2000, 2100}
vwma10 := tav.VWMA(price, volume, 10)
Streaming Calculations with Series
serie := tav.NewSeries(close)
smaSeries := tav.SMA(serie, 30)
latestSMA := smaSeries.Get(0) // Retrieve most recent value
Python Integration
import tav
close = [101, 102, 103, 104, 105, 106, 107, 108, 109, 110]
sma = tav.SMA(close, 5) # Returns [nan, nan, nan, nan, 103.0, 104.0, ...]
ema = tav.EMA(close, 5)
Summary
- BanTA provides 12 distinct moving average algorithms ranging from basic SMA to advanced adaptive methods like KAMA and ALMA.
- Each algorithm is available in two forms: slice-based functions in
tav/indicators.gofor batch processing and stateful methods insta_inds.gofor streaming data. - All implementations are NaN-tolerant, automatically handling gaps in market data without manual preprocessing.
- The library includes advanced low-lag options like HMA, KAMA, and ALMA for high-frequency trading applications.
- Python bindings in
python/tav/index.goexpose the same functionality to data science workflows.
Frequently Asked Questions
What is the difference between EMA and RMA in BanTA?
EMA (Exponential Moving Average) uses a smoothing factor of α = 2/(n+1), making it highly responsive to recent price changes. RMA (Relative Moving Average) implements Wilder’s smoothing with α = 1/n, which reacts more slowly and is preferred for indicators like RSI. BanTA provides both EMA() and RMA() in tav/indicators.go, plus variant functions EMABy() and RMABy() that allow custom initialization types.
How does BanTA handle missing data (NaN values) in moving average calculations?
All moving averages supported by BanTA are NaN-tolerant by design. When a math.NaN() value is encountered in the input slice, the output at that index becomes NaN, and the internal calculation state resets appropriately. This behavior is consistent across both the slice-based functions in tav/indicators.go and the stateful Series methods in sta_inds.go, ensuring robust handling of market data gaps without manual preprocessing.
Can I use BanTA moving averages in Python, or is it Go-only?
BanTA provides Python bindings through the python/tav/index.go file using gopy. You can import the tav module in Python and call the same moving average functions—such as tav.SMA(), tav.EMA(), and tav.VWMA()—with Python lists or arrays. The functions return Python lists of floats, maintaining the same NaN-handling semantics and calculation logic as the Go implementations.
Which moving average should I use for reducing lag in fast-moving markets?
For low-lag applications, BanTA offers three specialized options. The Hull Moving Average (HMA) combines weighted moving averages with square-root period scaling to minimize delay. The Kaufman Adaptive Moving Average (KAMA) automatically adjusts smoothing based on market efficiency, becoming more responsive during strong trends. Finally, the Arnaud Legoux Moving Average (ALMA) uses Gaussian-shaped weights to achieve superior smoothness with minimal lag. All three are available in tav/indicators.go as HMA(), KAMA(), and ALMA().
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →