How to Calculate KDJ Momentum Indicators Using BanTA: Go and Python Guide
BanTA computes KDJ momentum indicators through two execution models—state-caching for live trading bots and parallel computation for bulk backtesting—using the KDJ() function in either sta_inds.go or tav/indicators.go depending on your architecture.
BanTA is a high-performance technical analysis library written in Go with zero external dependencies. This guide explains how to calculate the KDJ momentum indicator using BanTA's dual execution models, referencing the actual implementation in sta_inds.go and tav/indicators.go.
Understanding BanTA's Dual Execution Models
BanTA provides two distinct execution models for technical analysis calculations:
State-caching (event-driven) mode uses a BarEnv object to store historic series for a symbol and timeframe. This mirrors TradingView's Pine Script behavior and updates cached values on each new candle, making it ideal for live-trading bots requiring incremental updates.
Parallel-computation mode exposes pure functions that accept plain []float64 slices and return full-length result arrays. This TA-Lib-style approach is optimized for bulk backtesting and research workloads where you process entire historical datasets at once.
How KDJ Works in BanTA
The KDJ indicator is a momentum oscillator that extends the Stochastic oscillator with an additional J line. BanTA implements the standard calculation pipeline:
-
RSV (Raw Stochastic Value):
RSV = 100 × (close − lowestLow) / (highestHigh − lowestLow)over the lookback period. This uses the same logic as BanTA'sStochfunction intav/indicators.goat line 838. -
K line: RMA (Running Moving Average) or SMA of RSV over
sm1periods, seeded with 50. -
D line: RMA or SMA of K over
sm2periods, also seeded with 50.
The choice between RMA and SMA smoothing is controlled by the maBy argument, which defaults to "rma" for exponential-like smoothing behavior.
Implementation Examples
State-Caching Mode for Live Trading
Use this approach when processing real-time market data streams where bars arrive sequentially.
Go Implementation
package main
import (
"fmt"
ta "github.com/banbox/banta"
)
var envMap = make(map[string]*ta.BarEnv)
func OnBar(symbol, timeframe string, k *ta.Kline) {
key := fmt.Sprintf("%s_%s", symbol, timeframe)
env, ok := envMap[key]
if !ok {
env = &ta.BarEnv{TimeFrame: timeframe, BarNum: 1}
envMap[key] = env
}
// feed the new candle
env.OnBar(k.Time, k.Open, k.High, k.Low, k.Close, k.Volume, k.Quote, k.BuyVolume, k.TradeNum)
// KDJ (period=9, sm1=3, sm2=3)
kLine, dLine, _ := ta.KDJ(env.High, env.Low, env.Close, 9, 3, 3)
fmt.Printf("K=%0.2f D=%0.2f (latest)\n", kLine.Get(0), dLine.Get(0))
}
This implementation references the KDJ function in sta_inds.go lines 697-715, which accepts *Series pointers for high, low, and close prices, plus integer parameters for period, sm1, and sm2 smoothing windows.
Python Implementation
from bbta import ta
# 1️⃣ create a BarEnv (one per symbol/timeframe)
env = ta.BarEnv(TimeFrame="5m")
# simulate incoming candles (timestamp, o, h, l, c, v)
candles = [
(1672531200000, 100, 102, 99, 101, 1200),
(1672531260000, 101, 103, 100, 102, 1300),
# … more candles …
]
for ts, o, h, l, c, v in candles:
env.OnBar(ts, o, h, l, c, v, 0, 0, 0)
# KDJ with default RMA smoothing
k, d, _ = ta.KDJ(env.High, env.Low, env.Close, 9, 3, 3)
print(f"K={k.Get(0):.2f} D={d.Get(0):.2f}")
The Python binding wraps the Go implementation in python/ta/index.go lines 25-30, exposing the same state-caching API to Python users.
Parallel Computation Mode for Backtesting
Use this approach when processing complete historical datasets where you need full arrays returned immediately.
Go Implementation
package main
import (
"fmt"
"github.com/banbox/banta/tav"
)
func main() {
high := []float64{1.02, 1.04, 1.03, 1.05, 1.06, 1.07, 1.05}
low := []float64{0.98, 0.99, 1.00, 1.01, 1.02, 1.00, 1.01}
close:= []float64{1.00, 1.02, 1.01, 1.04, 1.05, 1.03, 1.04}
k, d, _ := tav.KDJ(high, low, close, 9, 3, 3)
fmt.Printf("K series: %v\nD series: %v\n", k, d)
}
This calls the KDJ function in tav/indicators.go lines 856-861, which accepts []float64 slices and returns three []float64 slices representing the K, D, and J lines.
Python Implementation
from bbta import tav
high = [1.02, 1.04, 1.03, 1.05, 1.06, 1.07, 1.05]
low = [0.98, 0.99, 1.00, 1.01, 1.02, 1.00, 1.01]
close = [1.00, 1.02, 1.01, 1.04, 1.05, 1.03, 1.04]
k, d, _ = tav.KDJ(high, low, close, 9, 3, 3)
print("K:", k)
print("D:", d)
The Python wrapper in python/tav/index.go lines 172-179 exposes the parallel computation API to Python users, accepting Python lists or NumPy arrays and returning computed results.
Key Source Files and API Reference
| File | Purpose | Lines |
|---|---|---|
sta_inds.go |
State-caching series API including KDJ, Stoch, and RSI |
697-715 |
tav/indicators.go |
Parallel-computation functions including KDJ, SMA, and EMA |
856-861 |
python/ta/index.go |
Python wrapper for state-caching API | 25-30 |
python/tav/index.go |
Python wrapper for parallel-computation API | 172-179 |
core.go |
Core Series and BarEnv infrastructure |
- |
chanlun.go |
Additional caching infrastructure | - |
The KDJ function signature in state-caching mode accepts *Series pointers for price data and returns three *Series objects (K, D, J), while the parallel version accepts and returns []float64 slices.
Summary
- BanTA provides two execution models for KDJ calculations: state-caching via
BarEnvfor live trading, and parallel computation via thetavpackage for backtesting. - The KDJ implementation follows the standard formula: RSV calculation followed by smoothed K and D lines using RMA (default) or SMA, with source code located in
sta_inds.golines 697-715 andtav/indicators.golines 856-861. - Go developers import
github.com/banbox/bantafor state-caching orgithub.com/banbox/banta/tavfor parallel mode. - Python users access the same functionality through
bbta.ta.KDJ()for event-driven workflows andbbta.tav.KDJ()for batch processing.
Frequently Asked Questions
What parameters does BanTA's KDJ function accept?
The KDJ function accepts five required parameters: high, low, and close price series (either *Series objects for state-caching or []float64 slices for parallel mode), followed by three integers: period (the RSV lookback window, typically 9), sm1 (the K smoothing period, typically 3), and sm2 (the D smoothing period, typically 3). The state-caching version returns three *Series pointers (K, D, J), while the parallel version returns three []float64 slices.
How does BanTA's KDJ calculation differ from standard Stochastic?
While BanTA's RSV calculation uses the same formula as a standard Stochastic oscillator (RSV = 100 × (close − lowestLow) / (highestHigh − lowestLow)), the KDJ indicator adds the J line calculated as 3K − 2D. Additionally, BanTA allows you to choose between RMA (Running Moving Average, default) and SMA smoothing for the K and D lines via the maBy argument, with both methods seeding initial values at 50 to ensure consistent behavior across series.
Which execution mode should I use for live trading versus backtesting?
For live trading bots processing streaming market data, use the state-caching mode via BarEnv (Go) or bbta.ta (Python). This maintains running state across bars and computes only incremental updates, mirroring TradingView's Pine Script behavior and minimizing CPU overhead per tick. For backtesting and research requiring batch processing of complete historical datasets, use the parallel-computation mode via the tav package (Go) or bbta.tav (Python), which processes entire arrays without maintaining state and is optimized for vectorized operations across large datasets.
Does BanTA support other momentum indicators besides KDJ?
Yes, BanTA implements numerous momentum indicators in both execution modes. The state-caching API in sta_inds.go includes RSI, Stochastic, CCI, and MACD, while the parallel computation package in tav/indicators.go provides vectorized versions of SMA, EMA, RSI, and Stochastic calculations. All indicators follow the same dual-mode architecture, allowing seamless switching between event-driven live trading and batch backtesting workflows without changing your underlying calculation logic.
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 →