How to Use the MACD Indicator in BanTA Go: Raw Slices vs Series
To calculate MACD in BanTA Go, call tav.MACD() for raw []float64 slices or banta.MACD() for cached *Series objects that integrate with BarEnv environments.
The MACD indicator in BanTA Go is implemented across two architectural layers in the banbox/banta repository. The library provides both low-level mathematical operations in the tav package and high-level cached abstractions in the main banta package for backtesting workflows.
MACD Architecture in BanTA
BanTA separates indicator calculations into distinct layers to support both standalone analysis and integrated trading strategies.
Raw Slice Layer (tav Package)
The foundational implementation lives in main/tav/indicators.go and operates on primitive Go slices. The MACD function returns two []float64 slices representing the MACD line and signal line. This layer performs direct exponential moving average (EMA) calculations without caching or environment state.
Series Layer with Caching (banta Package)
The higher-level API in main/sta_inds.go returns *Series objects that automatically cache results per BarEnv. When you call banta.MACD(), the library generates a deterministic cache key (format: "_macd" + fast*1000 + slow*100 + smooth*10 + initType) and stores the result in the Series object, making subsequent calls O(1).
Raw Slice Implementation
For standalone calculations without environment setup, use the tav package functions directly from main/tav/indicators.go.
The algorithm follows the standard MACD specification:
- Calculate fast EMA (typically 12 periods)
- Calculate slow EMA (typically 26 periods)
- Subtract slow from fast to create the MACD line
- Calculate signal line as EMA of MACD line (typically 9 periods)
package main
import (
"fmt"
"github.com/banbox/banta/main/tav"
)
func main() {
// Simulated close prices
closes := []float64{101, 102, 103, 104, 105, 106, 107, 108, 109, 110}
// Standard parameters: fast=12, slow=26, smooth=9
macdLine, signalLine := tav.MACD(closes, 12, 26, 9)
fmt.Printf("MACD: %v\n", macdLine)
fmt.Printf("Signal: %v\n", signalLine)
}
For custom initialization types (such as MyTT compatibility), use MACDBy with the initType parameter:
// initType 0 = standard, 1 = MyTT/Chinese platform style
macd, signal := tav.MACDBy(closes, 12, 26, 9, 1)
Series-Based Implementation with Caching
When working within a BarEnv (the OHLCV container defined in main/core.go), use the cached Series API from main/sta_inds.go. This approach stores calculated values in the environment's cache using the Series.To method.
package main
import (
"fmt"
"github.com/banbox/banta"
)
func main() {
// Create environment: exchange, market, symbol, timeframe
env, _ := banta.NewBarEnv("binance", "spot", "BTCUSDT", "1d")
// Feed OHLCV bars (timestamp in milliseconds)
env.OnBar(1704067200000, 30000, 31000, 29500, 30000, 9e9, 8e9, 1000, 100)
env.OnBar(1704153600000, 30000, 32000, 29800, 31500, 9.5e9, 8.5e9, 1200, 110)
// Calculate MACD on Close series
macdSeries, signalSeries := banta.MACD(env.Close, 12, 26, 9)
// Retrieve latest values (index 0 = most recent)
fmt.Printf("Current MACD: %.4f\n", macdSeries.Get(0))
fmt.Printf("Current Signal: %.4f\n", signalSeries.Get(0))
// Access historical values
histMacd := macdSeries.Range(0, 5)
fmt.Println("Last 5 MACD values:", histMacd)
}
The caching mechanism checks res.Cached() (defined in main/types.go lines 48-57) before recalculating. If uncached, it computes EMABy for fast and slow periods, subtracts them using Series.Sub, then calculates the signal EMA.
Initialization Types: Standard vs MyTT
BanTA supports two EMA initialization methods via the initType parameter:
initType = 0: Standard initialization used by international platforms (default)initType = 1: MyTT initialization used by Chinese technical analysis platforms
The difference affects only the first EMA value calculation; subsequent values use identical smoothing formulas. Use MACDBy instead of MACD to specify this parameter:
// MyTT-style calculation
macdSeries, signalSeries := banta.MACDBy(env.Close, 12, 26, 9, 1)
Performance Considerations
The raw slice implementation in tav/indicators.go (lines 172-176 for EMABy, lines 355-383 for MACD) allocates new slices for each calculation with O(n) complexity where n is the data length.
The Series implementation adds O(1) cache lookup overhead but avoids recalculating indicators on historical bars when processing real-time data streams. The cache key incorporates all parameters (fast, slow, smooth, initType) to prevent collision between different MACD configurations on the same Series.
Summary
- Raw slices: Use
tav.MACD(data, fast, slow, smooth)inmain/tav/indicators.gofor standalone calculations without environment setup. - Cached Series: Use
banta.MACD(series, fast, slow, smooth)inmain/sta_inds.gowhen working withBarEnvobjects to enable automatic result caching. - Custom initialization: Append
Byto function names (MACDBy) and passinitType(0 or 1) for MyTT compatibility. - Cache keys: Generated as
"_macd" + fast*1000 + slow*100 + smooth*10 + initTypein the Series implementation. - Result access: Call
Series.Get(0)for the latest value orSeries.Range(start, end)for historical slices.
Frequently Asked Questions
What is the difference between tav.MACD and banta.MACD?
tav.MACD operates on raw []float64 slices and returns two float64 slices, suitable for data analysis outside trading environments. banta.MACD operates on *Series objects from a BarEnv, caches results using a deterministic key, and returns *Series pointers that maintain state across bar updates.
How does the caching mechanism work in BanTA MACD?
The Series implementation generates a cache key using the formula "_macd" + fast*1000 + slow*100 + smooth*10 + initType. It calls obj.To(key) to retrieve or create a cache slot, checks res.Cached() to avoid redundant calculation, and stores both MACD and signal values in the result object.
When should I use initType 1 instead of 0?
Use initType = 1 when replicating indicators from MyTT or Chinese trading platforms that use alternative EMA initialization. Use initType = 0 (default) for compatibility with international standards like TA-Lib or pandas-ta. The parameter affects only the first EMA value in the sequence.
How do I access the MACD histogram in BanTA?
BanTA returns the MACD line and signal line separately. Calculate the histogram by subtracting the signal from the MACD: histogram := macdSeries.Sub(signalSeries) or manually subtract the slices when using the raw API.
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 →