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)insta_inds.go(lines 174-182) - Parallel:
tav.EMABy(data, period, initType)intav/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.EMAfor state-caching event-driven trading andtav.EMAfor parallel batch analysis. - State-caching mode stores intermediate results in
*Seriesobjects, enabling O(1) incremental updates as new bars arrive viasta_inds.go. - Parallel mode processes complete
[]float64slices in a single pass without persistent state, optimized for research workloads viatav/indicators.go. - Both use the same mathematics: smoothing factor
α = 2/(period+1)with configurable initialization viaEMAByfunctions (SMA seed or first-value seed). - Python bindings mirror the Go API exactly, exposing
bbta.tafor state-caching andbbta.tavfor 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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →