How to Implement SMA Indicator Using BanTA: Complete Go and Python Guide
To implement an SMA indicator using BanTA, call the SMA function from the tav package for raw []float64 slices, or use the SMA method on *Series objects for cached, chainable calculations that automatically handle window sums and division by the period.
BanTA is a high-performance technical analysis library written in Go with Python bindings, designed for financial time-series processing. When you implement SMA indicator using BanTA, you gain access to two distinct architectural layers: a low-level raw slice interface for simple calculations and a high-level Series API with built-in caching for complex indicator chaining.
Understanding BanTA's SMA Architecture
BanTA provides SMA calculations through two complementary APIs that share the same underlying mathematics but differ in memory management and ease of use.
The Raw Slice API operates directly on []float64 slices, computing window sums with the Sum function and dividing by the period to produce the average. This approach is stateless and ideal for one-off calculations.
The Series API wraps data in a *Series object that maintains a cache of computed values. When you call SMA on a Series, BanTA creates a derived series (internally tagged as _sma), calculates the rolling sum, and reuses cached results on subsequent accesses. This design minimizes redundant computation when chaining multiple indicators.
Implementing SMA with the Raw Slice API
Source Code Location and Logic
The raw slice implementation resides in tav/indicators.go at lines 61–74. This function accepts a slice of float64 values and an integer period, delegates the window calculation to the Sum function, and divides each valid sum by float64(period) to produce the simple moving average.
The implementation handles NaN values gracefully: if any value within a window is NaN, the resulting SMA value for that position becomes NaN, and calculation resumes only after the NaN exits the window.
Complete Go Example
package main
import (
"fmt"
"github.com/banbox/banta/main/tav"
)
func main() {
// Example closing prices
close := []float64{10, 11, 12, 13, 14, 15, 16}
period := 3
// Compute SMA – returns a slice of the same length
sma := tav.SMA(close, period)
fmt.Println("SMA:", sma)
// Output: SMA: [NaN NaN 11 12 13 14 15]
}
Explanation: The first period-1 entries return NaN because the sliding window is not yet full. Once the window contains three values, the function calculates the average (e.g., (10+11+12)/3 = 11).
Implementing SMA with the Series API
Cached Calculation Architecture
The high-level implementation is located in sta_inds.go at lines 87–101. This version operates on *Series objects defined in core.go and types.go. When you invoke SMA(series, period), BanTA:
- Creates a new derived series tagged
_smathat references the parent series - Computes the rolling sum using
Sum(series, period) - Divides each valid sum by the period to produce the average
- Caches the result so subsequent indicator chains reuse the computed values without recalculation
This caching mechanism is particularly efficient when building complex strategies that reference the same SMA multiple times or chain it with other indicators like RSI or Bollinger Bands.
Complete Go Example
package main
import (
"fmt"
. "github.com/banbox/banta/main"
)
func main() {
// Build a Series from raw data
close := NewSeries([]float64{10, 11, 12, 13, 14, 15, 16})
period := 3
// Compute SMA – result is a cached Series
sma := SMA(close, period)
// Print the SMA values
for i := 0; i < sma.Len(); i++ {
fmt.Printf("index %d: %.2f\n", i, sma.Get(i))
}
}
Explanation: The NewSeries function wraps the raw slice in a Series object. The SMA function returns a new Series that automatically handles the rolling window logic and caches results. Accessing values via Get(i) retrieves the computed SMA or NaN for incomplete windows.
Using SMA in Python
Python Bindings Structure
BanTA exposes its Go implementation to Python using gopy, which compiles the Go functions into a shared library. The Python bindings are located in python/tav/index.go for the raw slice API and python/ta/index.go for the Series API.
When you call banta.ta.SMA(series, period) from Python, the wrapper forwards the arguments to the Go library, which performs the calculation and returns a Python-accessible Series object containing the SMA values.
Python Implementation Example
import banta.ta as ta
import numpy as np
# Example closing prices (numpy array or Python list)
close = np.array([10, 11, 12, 13, 14, 15, 16], dtype=float)
period = 3
# Compute SMA – returns a banta Series object
sma = ta.SMA(close, period)
# Convert to a plain list for inspection
print("SMA:", list(sma))
# Output: SMA: [nan, nan, 11.0, 12.0, 13.0, 14.0, 15.0]
Explanation: The Python API accepts numpy arrays or Python lists and automatically converts them to the internal Series format. The returned object behaves like a list, where the first period-1 values are nan (Python's float nan) indicating insufficient data for the calculation.
Handling Edge Cases and NaN Values
BanTA's SMA implementation includes robust handling of NaN values and incomplete windows. When calculating the simple moving average, if any value within the current window is NaN, the resulting SMA value for that position becomes NaN. The calculation automatically resumes once the NaN value exits the sliding window.
This behavior ensures that missing data does not contaminate subsequent valid calculations. For the Series API, the cache respects these NaN boundaries, ensuring that derived indicators built on top of the SMA receive the correct NaN signals when underlying data is incomplete or missing.
Key Source Files Reference
The SMA implementation spans several files across the BanTA repository:
tav/indicators.go(lines 61–74): Contains the low-levelSMAfunction for[]float64slices, implementing the core sum-and-divide logic.sta_inds.go(lines 87–101): Implements the high-levelSMAmethod for*Seriesobjects with caching support.python/tav/index.go(lines 25–27): Python binding that exposes the raw slice SMA function to Python via gopy.python/ta/index.go(lines 35–36): Python binding for the Series-based SMA calculation.core.goandtypes.go: Define theSeriesstruct and caching mechanisms used by the high-level API.
Summary
- BanTA provides two APIs to implement SMA indicator using BanTA: the Raw Slice API for simple
[]float64calculations and the Series API for cached, chainable technical analysis. - The raw implementation in
tav/indicators.gocomputes window sums and divides by the period, returningNaNfor incomplete windows. - The Series implementation in
sta_inds.gocreates a derived_smaseries that caches results, making repeated calculations and indicator chaining computationally efficient. - Python bindings in
python/tav/index.goandpython/ta/index.goexpose both APIs via gopy, accepting numpy arrays and returning Series objects. - Both implementations handle
NaNvalues gracefully, ensuring calculation integrity when data is missing.
Frequently Asked Questions
What is the difference between the Raw Slice API and Series API in BanTA?
The Raw Slice API operates directly on []float64 slices and performs stateless calculations, making it ideal for simple, one-off SMA computations. The Series API wraps data in a *Series object that maintains a cache of computed values, allowing efficient reuse when chaining multiple indicators or referencing the same SMA calculation repeatedly in your strategy.
How does BanTA handle incomplete windows when calculating SMA?
BanTA returns NaN (Not a Number) for any position where the sliding window does not contain enough data points to satisfy the specified period. For a period of 3, the first two values in the result will be NaN, and valid SMA calculations begin at the third position. This behavior applies consistently across both the Go implementations and Python bindings.
Can I use BanTA SMA with Python numpy arrays?
Yes, the Python bindings accept numpy arrays or standard Python lists as input. When you call banta.ta.SMA(close, period), the library automatically converts the input into the internal Series format, computes the SMA using the compiled Go code, and returns a Series object that behaves like a list and can be converted back to numpy arrays if needed.
Where is the SMA calculation cached in the Series API?
The cache is stored within the derived Series object created when you call SMA on a Series. Internally, BanTA tags this derived series as _sma and stores the computed rolling sum and division results. Subsequent accesses to the same SMA series object retrieve values from this cache rather than recalculating the window sum, significantly improving performance when the same indicator is referenced multiple times.
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 →