How to Calculate EMA with BanTA: State-Caching vs Parallel Methods

BanTA calculates EMA using either a state-caching event-driven API (ta.EMA) for live trading or a parallel batch API (tav.EMA) for offline analysis, both implementing the standard exponential smoothing formula with α = 2/(period+1).

The banbox/banta repository provides a high-performance technical analysis library for Go and Python. When you need to calculate EMA with BanTA, you can choose between two optimized implementations designed for different execution contexts: incremental state-caching for streaming market data and vectorized batch processing for historical research.

Two Ways to Calculate EMA with BanTA

BanTA exposes EMA functionality through two distinct packages that share the same mathematical core but differ in data structures and performance characteristics.

State-Caching Mode (Event-Driven)

The ta package provides state-caching EMA designed for live trading and back-testing scenarios where each new candle arrives incrementally.

In sta_inds.go (lines 187-200), the EMA function operates on a *Series object:

func EMA(obj *Series, period int) *Series

This implementation caches intermediate results inside the Series struct, allowing O(1) updates when new data arrives. The function initializes the first EMA value using a Simple Moving Average (SMA) by default (initType = 0).

Parallel Computation Mode (Batch)

The tav package provides parallel EMA optimized for offline analysis where the entire dataset is available upfront.

In tav/indicators.go (lines 167-172), the EMA function accepts a raw slice of floats:

func EMA(data []float64, period int) []float64

This implementation processes the entire array in a single pass without maintaining state between calls, making it ideal for vectorized operations on historical price data.

Core Implementation Details

Both EMA implementations rely on the same exponential smoothing formula with a smoothing factor α = 2 / (period + 1).

Mathematical Foundation

The weight calculation appears in sta_inds.go (lines 174-180):

alpha := 2.0 / float64(period+1)

This standard EMA multiplier ensures that newer values receive exponentially more weight than older observations.

Initialization Strategies

BanTA supports two initialization types via the EMABy functions:

initType Behavior Use Case
0 Initialize with SMA of first period values Standard technical analysis (default)
1 Initialize with first valid data point Custom strategies requiring immediate EMA availability

Access these variants through:

  • State-caching: ta.EMABy(series, period, initType) in sta_inds.go (lines 174-182)
  • Parallel: tav.EMABy(data, period, initType) in tav/indicators.go (lines 172-176)

Code Examples

State-Caching EMA in Go

Use this pattern for live trading systems processing streaming candles:

package main

import (
	"fmt"
	ta "github.com/banbox/banta"
)

func main() {
	// Initialize environment for 1-minute timeframe
	env := &ta.BarEnv{TimeFrame: "1m"}

	// Simulate incoming market data
	candles := []ta.Kline{
		{Time: 1, Open: 100, High: 101, Low: 99, Close: 100, Volume: 500},
		{Time: 2, Open: 100, High: 102, Low: 99, Close: 101, Volume: 600},
		{Time: 3, Open: 101, High: 103, Low: 100, Close: 102, Volume: 700},
	}

	// Process each candle incrementally
	for _, k := range candles {
		env.OnBar(k.Time, k.Open, k.High, k.Low, k.Close, k.Volume, 0, 0, 0)
	}

	// Calculate EMA(12) on closing prices
	emaSeries := ta.EMA(env.Close, 12)
	
	fmt.Printf("Current EMA(12) = %.4f\n", emaSeries.Get(0))
}

The env.Close *Series automatically caches historical values, enabling efficient incremental updates via the implementation in sta_inds.go.

Parallel EMA in Go

Use this approach for back-testing or research on complete datasets:

package main

import (
	"fmt"
	"github.com/banbox/banta/tav"
)

func main() {
	closePrices := []float64{100, 101, 102, 103, 105, 106, 108, 107, 109, 110}
	period := 5

	// Compute entire EMA series in one call
	ema := tav.EMA(closePrices, period)

	fmt.Println("EMA values:", ema)
}

This calls the vectorized implementation in tav/indicators.go (lines 167-172), processing the full array without maintaining state between calls.

State-Caching EMA in Python

The Python bindings mirror the Go API for event-driven strategies:

from bbta import ta

# Initialize environment for 1-minute chart

env = ta.BarEnv(TimeFrame="1m")

# Feed historical candles (timestamp, open, high, low, close, volume)

candles = [
    (1, 100, 101, 99, 100, 500),
    (2, 100, 102, 99, 101, 600),
    (3, 101, 103, 100, 102, 700),
]

for ts, o, h, l, c, v in candles:
    env.OnBar(ts, o, h, l, c, v, 0, 0, 0)

# Calculate EMA(12) on closing prices

ema_series = ta.EMA(env.Close, 12)

print("Current EMA(12) =", ema_series.Get(0))

The bbta Python package wraps the same Go logic found in sta_inds.go, providing identical state-caching behavior.

Parallel EMA in Python

For Jupyter notebooks or batch analysis:

from bbta import tav

close_prices = [100, 101, 102, 103, 105, 106, 108, 107, 109, 110]
period = 5

ema = tav.EMA(close_prices, period)
print("EMA:", ema)

This accesses the vectorized implementation in tav/indicators.go through the Python bindings.

Key Files and Functions

Understanding the source structure helps debug calculations and optimize performance:

File Function Lines Purpose
sta_inds.go EMA(obj *Series, period int) 187-200 State-caching EMA for live trading
sta_inds.go EMABy(obj *Series, period, initType int) 174-182 Configurable initialization for state-caching
tav/indicators.go EMA(data []float64, period int) 167-172 Parallel batch EMA for offline analysis
tav/indicators.go EMABy(data []float64, period, initType int) 172-176 Configurable initialization for parallel mode

Both implementations rely on the ewma helper routine that applies the exponential smoothing formula with α = 2/(period+1).

Summary

  • BanTA offers two EMA implementations: ta.EMA for state-caching event-driven trading and tav.EMA for parallel batch analysis.
  • State-caching mode stores intermediate results in *Series objects, enabling O(1) incremental updates as new bars arrive via sta_inds.go.
  • Parallel mode processes complete []float64 slices in a single pass without persistent state, optimized for research workloads via tav/indicators.go.
  • Both use the same mathematics: smoothing factor α = 2/(period+1) with configurable initialization via EMABy functions (SMA seed or first-value seed).
  • Python bindings mirror the Go API exactly, exposing bbta.ta for state-caching and bbta.tav for parallel computation.

Frequently Asked Questions

What is the difference between ta.EMA and tav.EMA in BanTA?

ta.EMA operates on *Series objects and caches state between calculations, making it ideal for live trading systems that process incoming candles incrementally. tav.EMA accepts plain []float64 slices and computes the entire series in a single batch without maintaining state, which is optimal for back-testing and research scenarios where the full dataset is available upfront.

How does BanTA initialize the first EMA value?

By default, both ta.EMA and tav.EMA initialize the first value using a Simple Moving Average (SMA) of the first period data points (initType = 0). You can change this behavior by calling EMABy instead and passing initType = 1, which initializes the EMA with the first valid (non-NaN) data point rather than the SMA.

Can I use BanTA EMA calculations in Python?

Yes, BanTA provides Python bindings through the bbta package that expose identical functionality to the Go API. You can calculate EMA using state-caching mode with bbta.ta.EMA(env.Close, period) for live trading applications, or use bbta.tav.EMA(close_prices, period) for batch analysis in Jupyter notebooks or research scripts.

What is the smoothing factor formula used in BanTA EMA?

BanTA calculates the smoothing factor α using the standard technical analysis formula α = 2 / (period + 1), as implemented in sta_inds.go (lines 174-180). This weight determines how much influence the newest price observation has on the current EMA value, with higher periods resulting in smaller alpha values and smoother EMA curves.

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 →