Indicators
Supports TA-Lib and pandas_ta with hundreds of technical indicators. Calculate thousands of stocks over long time periods with a single line, suitable for individual stock analysis and machine learning.
Installing TA-Lib
- Local environment: see the official installation guide; supports Windows, MacOS, and Linux.
- Google Colab:
For more parameters and functions, see the TA-Lib official documentation.
Computing RSI for All Stocks
Use data.indicator() to compute RSI (timeperiod=14) for every stock in the active market:
from finlab import data
data.set_market('us')
rsi = data.indicator('RSI', timeperiod=14)
rsi[['AAPL', 'MSFT', 'NVDA']].tail()
The result is a DataFrame indexed by date with one column per ticker. The first 14 days are NaN because there is not enough data yet. By default the indicator uses unadjusted prices; pass adjust_price=True for adjusted prices, or resample='W' for weekly bars.
Technical Indicators with Two Time Series (Stochastic Oscillator KD)
Use data.indicator('STOCH') to compute the Stochastic Oscillator (KD values), which returns two DataFrames (K and D).
Stock Screening Using KD Values
List stocks where K > D on the most recent day:
(k > d).iloc[-1] is a boolean Series indexed by ticker for the latest date.
Indicators Beyond the Classic Set
data.indicator() looks up TA-Lib first, by upper-case name. Newer TA-Lib releases include indicators such as SuperTrend, which returns the trend line and its direction (1 up, -1 down):
When TA-Lib has no function of that name, a lower-case name is computed with pandas_ta if it is installed (it may be slower).
Custom Indicators (Pandas Operations)
Build custom indicators directly with Pandas operations, no TA-Lib required:
Price & Volume Indicators
from finlab import data
data.set_market('us')
close = data.get('price:adj_close')
volume = data.get('price:volume')
revenue = data.get('us_income_statement:revenue') # quarterly
# Momentum: N-day return
momentum_20 = close / close.shift(20) - 1
# Moving average deviation
ma60 = close.average(60)
bias = (close - ma60) / ma60
# Price-volume divergence: price at high but volume shrinking
price_high = close == close.rolling(60).max()
volume_low = volume < volume.average(20)
divergence = price_high & volume_low
# Quarterly revenue growth
rev_yoy = revenue / revenue.shift(4) - 1 # year-over-year
rev_qoq = revenue / revenue.shift(1) - 1 # quarter-over-quarter
rev_trend = (
revenue.rolling(2).mean() / revenue.rolling(4).mean() - 1
) # last 2 vs last 4 quarters
Factor Standardization with .cs
eps = data.get('us_income_statement:eps_diluted')
net_income = data.get('us_income_statement:net_income')
equity = data.get('us_balance_sheet:total_stockholders_equity')
raw_close = data.get('price:close') # unadjusted price for valuation
pe = raw_close / eps.rolling(4).sum() # trailing-12-month P/E
roe = net_income / equity[equity > 0] # quarterly ROE, positive equity only
# Multi-factor composite: standardize then equal-weight sum
score = roe.cs.zscore() + (-pe).cs.zscore() # higher ROE, lower PE = better
# Select top 10% by composite score
position = score.cs.rank() > 0.9
Sector Neutralization with .sector
# Problem: raw ROE selection overweights high-ROE sectors (e.g., technology)
# Solution: within-sector standardization selects "sector standouts"
profile = data.get('us_company_profile')
sectors = dict(zip(profile['symbol'], profile['sector']))
roe_neutral = roe.sector(sectors).zscore() # sector-neutralized
rev_neutral = rev_yoy.sector(sectors).zscore() # revenue growth also neutralized
# Composite factor
score = roe_neutral + rev_neutral
position = score.cs.rank() > 0.8
# Or use within-sector ranking directly
position = roe.sector(sectors).rank() > 0.7 # top 30% ROE within each sector
Without a mapping, .sector uses the Taiwan industry classification; for U.S. stocks always pass one.
Weight Construction with .weight
from finlab.backtest import sim
position = score.cs.rank() > 0.8
# Refined weights: inverse volatility + turnover limit
weights = position.weight.inverse_volatility(
window=60, price=close
).weight.limit_turnover(max_turnover=0.3)
report = sim(weights, resample='Q')
inverse_volatility() reads Taiwan prices unless you pass price. weight.cap_industry() caps Taiwan industry weights and is Taiwan market only.
Full accessor documentation
See finlab.dataframe reference for all .cs, .sector, and .weight methods.