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:

  1. Creates a new derived series tagged _sma that references the parent series
  2. Computes the rolling sum using Sum(series, period)
  3. Divides each valid sum by the period to produce the average
  4. 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-level SMA function for []float64 slices, implementing the core sum-and-divide logic.
  • sta_inds.go (lines 87–101): Implements the high-level SMA method for *Series objects 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.go and types.go: Define the Series struct 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 []float64 calculations and the Series API for cached, chainable technical analysis.
  • The raw implementation in tav/indicators.go computes window sums and divides by the period, returning NaN for incomplete windows.
  • The Series implementation in sta_inds.go creates a derived _sma series that caches results, making repeated calculations and indicator chaining computationally efficient.
  • Python bindings in python/tav/index.go and python/ta/index.go expose both APIs via gopy, accepting numpy arrays and returning Series objects.
  • Both implementations handle NaN values 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →