Five Python Trading Indicators: Specify Seeds, Warm-Up and Edge Cases
TECH INSIGHT / EXPLAINED
Indicator names do not fully specify their calculation. Seed values, warm-up length, standard-deviation convention and missing bars can change the output even when the visible period is identical.
Local execution of the actual project
These captures show the existing project UI or functions executed locally with non-private sample inputs. Each caption states the scope of the execution.
Five measurements, five contracts
SMA averages a fixed window; EMA recursively weights recent observations. RSI compares smoothed gains and losses. MACD subtracts two EMAs and compares the result with a signal average. Bollinger Bands add a multiple of standard deviation around an average. ATR smooths true range, including gaps from the previous close. None of these definitions is a trading-profit claim.
For reproducibility, the implementation below uses SMA-seeded Wilder smoothing for RSI and ATR, population deviation (ddof=0) for bands, and first-value-seeded recursive EMA (adjust=False). This EMA convention may differ from libraries using an SMA seed.
import numpy as np
import pandas as pd
def wilder(values, period):
if not isinstance(period, int) or isinstance(period, bool) or period < 1:
raise ValueError('positive integer period required')
values = pd.Series(values, dtype=float)
if not np.isfinite(values).all():
raise ValueError('finite contiguous input required')
out = pd.Series(np.nan, index=values.index, dtype=float)
if len(values) < period: return out
out.iloc[period-1] = values.iloc[:period].mean()
for i in range(period, len(values)):
out.iloc[i] = (out.iloc[i-1]*(period-1)+values.iloc[i])/period
return out
def indicators(frame, period=14):
x = frame[['high','low','close']].astype(float)
if x.empty or not np.isfinite(x.to_numpy()).all():
raise ValueError('finite OHLC data required')
if not ((x.low <= x.close) & (x.close <= x.high) & (x.low > 0)).all():
raise ValueError('invalid price bounds')
c = x.close
out = pd.DataFrame(index=x.index)
out['sma20'] = c.rolling(20, min_periods=20).mean()
out['ema20'] = c.ewm(span=20, adjust=False, min_periods=20).mean()
d = c.diff().iloc[1:]
g, l = wilder(d.clip(lower=0), period), wilder(-d.clip(upper=0), period)
rsi = 100*g/(g+l)
rsi = rsi.mask((g == 0) & (l == 0), 50) # explicit flat-market convention
out['rsi'] = rsi.reindex(x.index)
fast = c.ewm(span=12, adjust=False, min_periods=12).mean()
slow = c.ewm(span=26, adjust=False, min_periods=26).mean()
out['macd'] = fast-slow
out['signal'] = out.macd.ewm(span=9, adjust=False, min_periods=9).mean()
out['hist'] = out.macd-out.signal
sd = c.rolling(20, min_periods=20).std(ddof=0)
out['bb_low'], out['bb_high'] = out.sma20-2*sd, out.sma20+2*sd
prev = c.shift(1)
tr = pd.concat([x.high-x.low,(x.high-prev).abs(),(x.low-prev).abs()],axis=1).max(axis=1)
out['atr'] = wilder(tr.iloc[1:],period).reindex(x.index)
return outState the edge cases, not an epsilon
Fourteen RSI changes require fifteen closing observations. With gains but no losses, RSI is 100; with losses but no gains, it is 0. With neither, this example explicitly chooses 50. Another library may choose 0 or unavailable for that flat case, so do not promise a chart match without checking its convention. Replacing every zero loss with 1e-9 hides that choice and changes the scale.
ATR here starts with the first bar that has a previous close; its initial range window therefore also needs one extra bar. The input must already be chronological, unique and complete under your chosen missing-bar policy.
Test before interpreting
For close values 10,11,10,12 and period 3, gains average 1, losses average 1/3 and RSI is 75. A constant close has zero population band width; constant high–low range two gives ATR two after warm-up. Use these hand-checkable cases before comparing a long chart.
A narrow band does not predict the direction or timing of a breakout, and an RSI threshold is not an instruction to buy. Apply completed-bar signals to a later executable price, compare parameter neighborhoods and test costs on held-out data. Several correlated indicators do not provide several independent confirmations.
Sources and further reading
TA-Lib RSI formula · TA-Lib Wilder smoothing · pandas ewm conventions · Bollinger original explanation
Content and examples reviewed: 2026-09-29
댓글
댓글 쓰기