Guides
Technical indicators
On this page7
data.indicator() supports TA-Lib and pandas_ta with hundreds of technical indicators. One line calculates thousands of stocks over long time periods, for individual stock analysis or machine learning. The result is a date-by-ticker table, like data.get(), so you can use it directly in a stock-selection rule.
Install TA-Lib
!pip install ta-libSee the official installation guide; it supports Windows, MacOS, and Linux.
For more parameters and functions, see the TA-Lib official documentation.
Compute RSI for every stock
Pass the indicator's name and parameters to data.indicator(), for example RSI (timeperiod=14):
from finlab import data
data.set_market('us')
rsi = data.indicator('RSI', timeperiod=14)
rsi[['AAPL', 'MSFT', 'NVDA']].tail()- It computes every stock in the active market. The result is a DataFrame indexed by date with one column per ticker.
- The first 14 days are
NaNbecause there is not enough data yet. - By default the indicator uses unadjusted prices; pass
adjust_price=Truefor adjusted prices, orresample='W'for weekly bars.
Compute a two-line indicator: Stochastic (KD)
data.indicator('STOCH') computes the Stochastic Oscillator (KD values) and returns two DataFrames (K and D):
from finlab import data
data.set_market('us')
k, d = data.indicator('STOCH')
kPick stocks where K is above D
List stocks where K > D on the most recent day:
signal = (k > d).iloc[-1]
signal[signal].index # tickers with K above D on the latest date(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):
from finlab import data
data.set_market('us')
supertrend, direction = data.indicator('SUPERTREND')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).
Build your own indicators with Pandas
Build custom indicators directly with Pandas operations, no TA-Lib required.
Momentum, moving-average deviation and revenue growth
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 quartersCombine factors into one score (.cs)
.cs computes across all stocks on each date. Standardize each factor, then add them with equal weight:
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.9Neutralize by sector (.sector)
Selecting on raw ROE overweights sectors where ROE is high anyway. Standardizing within each sector picks the standouts of each sector instead:
# 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 sectorWithout a mapping, .sector uses the Taiwan industry classification; for U.S. stocks always pass one.
Set weights and backtest (.weight)
Once you have a selection, .weight sets each holding's weight; then hand the weights to sim():
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)
.rebalance('QE') # keep rebalance dates only, so turnover is per rebalance
.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.
See the finlab.dataframe reference for all .cs, .sector, and .weight methods.
Next steps
- Technical indicator selection A complete U.S. strategy built on technical indicators.
- Write better rules Take the top names by rank, combine conditions, set entries and exits.
- Backtesting Rebalance frequency, stops, fees and the trade log.
- finlab.dataframe .cs, .sector, .weight and other FinlabDataFrame methods.
Was this page helpful?