Technical Analysis (wraquant.ta)

263 indicators across 19 sub-modules, covering every category of technical analysis: moving averages, momentum oscillators, volume studies, trend detection, volatility measurement, candlestick patterns, cycle analysis, Fibonacci tools, support/resistance, market breadth, and exotic indicators.

Every indicator accepts pd.Series (or OHLCV components) and returns either a pd.Series or a dict[str, pd.Series] for multi-output indicators.

Quick Example

from wraquant.ta import rsi, macd, bollinger_bands, adx, atr, crossover

# Momentum: RSI and MACD
rsi_values = rsi(close, period=14)
macd_result = macd(close)   # {'macd', 'signal', 'histogram'}

# Volatility bands
bb = bollinger_bands(close, period=20, std_dev=2.0)
# bb['upper'], bb['middle'], bb['lower']

# Trend strength (ADX > 25 = strong trend)
adx_values = adx(high, low, close, period=14)

# Signal generation: EMA crossover
from wraquant.ta import ema
fast = ema(close, period=10)
slow = ema(close, period=50)
buy_signal = crossover(fast, slow)

Candlestick Patterns

from wraquant.ta import doji, engulfing, hammer, morning_star

# Each pattern returns a boolean Series
dojis = doji(open, high, low, close)
engulfings = engulfing(open, high, low, close)
hammers = hammer(open, high, low, close)

print(f"Doji days: {dojis.sum()}")
print(f"Engulfing days: {engulfings.sum()}")

Advanced Smoothing

from wraquant.ta import alma, jma, supersmoother

# ALMA: Arnaud Legoux Moving Average (low lag, low noise)
alma_values = alma(close, period=21)

# JMA: Jurik Moving Average (adaptive smoothing)
jma_values = jma(close, period=14)

# Super Smoother (Ehlers 2-pole filter)
ss = supersmoother(close, period=10)

Support & Resistance Detection

from wraquant.ta import find_support_resistance, supply_demand_zones

levels = find_support_resistance(close, n_levels=5)
print(f"Support levels: {levels['support']}")
print(f"Resistance levels: {levels['resistance']}")

zones = supply_demand_zones(open, high, low, close)
print(f"Supply zones: {zones['supply']}")
print(f"Demand zones: {zones['demand']}")

See also

API Reference

Technical analysis indicators for wraquant.

This package provides over 200 technical analysis indicators organised into 19 sub-modules. Every indicator accepts pd.Series (or OHLCV components) and returns either a pd.Series or a dict[str, pd.Series] for multi-output indicators.

Sub-modules

The sub-modules are designed to cover the full taxonomy of technical analysis, from classical chart overlays to exotic oscillators:

Price overlays (drawn on the price chart):

  • overlap – Moving averages and band studies. Start here for trend identification. SMA/EMA for trend direction, Bollinger Bands and Keltner Channel for volatility envelopes, Ichimoku for multi-timeframe support/resistance, Supertrend for trend-following signals.

  • trend – Trend direction and strength. ADX measures trend strength (not direction); values >25 indicate a strong trend. Aroon identifies trend starts. PSAR provides trailing stops. Heikin Ashi smooths price bars. ZigZag filters noise for swing analysis.

Oscillators (plotted in separate panels):

  • momentum – Speed and magnitude of price moves. RSI (14-period) is the most popular; >70 = overbought, <30 = oversold. MACD captures trend momentum via EMA crossovers. Stochastic compares close to range. Use TSI or CMO for smoother momentum signals. Squeeze Histogram detects volatility contraction breakouts.

  • volume – Volume-confirmed signals. OBV (On-Balance Volume) trends with the dominant side. CMF (Chaikin Money Flow) measures buying vs selling pressure. MFI is “volume-weighted RSI.” Force Index combines price change and volume.

  • performance – Relative performance and drawdown analytics. Alpha, tracking error, and up/down capture ratios for benchmark comparison. Rolling max drawdown and pain index for risk monitoring.

Volatility measurement (separate panel or overlay):

  • volatility – ATR (Average True Range) is the standard volatility measure for position sizing. Bollinger Width and Keltner Width measure squeeze/expansion. Garman-Klass, Parkinson, Rogers-Satchell, and Yang-Zhang use OHLC data for more efficient volatility estimation. Ulcer Index measures downside volatility.

Pattern recognition:

  • patterns – 38 candlestick patterns (Doji, Engulfing, Morning Star, Evening Star, Hammer, Three White Soldiers, etc.). Each returns a boolean Series marking pattern occurrences. Use for confirmation, not as standalone signals.

  • candles – Structural candlestick analytics: body size, shadow ratios, body-to-range ratio, inside/outside bars, pin bars. Useful as features for ML models.

  • price_action – Higher highs/lows for trend structure. Swing highs/lows for support/resistance. Gap analysis, range expansion, narrow range (NR4/NR7), key reversals.

Signal generation:

  • signals – Utility functions for combining indicators: crossover, crossunder, above/below, rising/falling, highest/lowest, normalize. These are building blocks for strategy logic.

Market breadth (for indices / baskets):

  • breadth – Advance/Decline line and ratio, McClellan Oscillator and Summation Index, Arms Index (TRIN), new highs/lows, percent above MA. Use these to confirm or diverge from index-level trends.

Statistical overlays:

  • statistics – Z-score, percentile rank, skewness, kurtosis, entropy, Hurst exponent, rolling beta and R-squared. These bridge technical and quantitative analysis.

Cycle analysis:

  • cycles – Hilbert Transform dominant period and trend mode, sine wave indicators, bandpass and roofing filters, Even Better Sinewave. Use when you suspect periodic structure (e.g., inventory or seasonal cycles).

Fibonacci analysis:

  • fibonacci – Retracements, extensions, fans, time zones, pivot points, and auto-Fibonacci (automatically finds swing points).

Advanced smoothing:

  • smoothing – ALMA (Arnaud Legoux), JMA (Jurik), Butterworth, Super Smoother, Gaussian, windowed MAs (Hann, Hamming). Use when standard MAs are too laggy or noisy.

Custom / advanced indicators:

  • custom – Squeeze Momentum, Anchored VWAP, Ehlers Fisher Transform, Adaptive RSI, Linear Regression Channel, Market Structure, Volume-Weighted MACD. Power tools for experienced analysts.

Exotic / lesser-known indicators:

  • exotic – Choppiness Index (ranging vs trending), Random Walk Index, Polarized Fractal Efficiency, Ergodic Oscillator, Elder Thermometer, KAIRI, Connors TPS. Niche but valuable for specific strategies.

Support and resistance:

  • support_resistance – Algorithmic detection of support/resistance levels, fractal levels, price clustering, round numbers, supply/demand zones, and trendline detection.

How to choose indicators

  1. Identify the market condition first: trending or ranging? Use ADX > 25 to confirm trend, Choppiness Index > 61.8 for range.

  2. For trending markets: use trend-following indicators (EMA crossovers, MACD, Supertrend, PSAR). Avoid mean-reversion oscillators (RSI, Stochastic) as standalone signals.

  3. For ranging markets: use oscillators (RSI, Stochastic, CCI) at overbought/oversold levels. Bollinger Bands for mean-reversion entries.

  4. Always confirm with volume (OBV, CMF) or breadth (A/D line).

  5. For ML feature engineering: prefer continuous indicators (candle ratios, Z-scores, ATR-normalized values) over boolean pattern detectors. See wraquant.ml.features.technical_features.

sma(data, period=20)[source]

Simple Moving Average.

The most fundamental overlay indicator. Smooths price by averaging the last period values equally.

Interpretation:
  • Price above SMA: Bullish – price is above its average.

  • Price below SMA: Bearish – price is below its average.

  • Golden cross: Short-term SMA (e.g. 50) crosses above long-term SMA (e.g. 200) = bullish trend signal.

  • Death cross: Short-term SMA crosses below long-term SMA = bearish trend signal.

  • Slope: Rising SMA confirms uptrend; falling confirms downtrend.

  • Common periods: 20 (short-term), 50 (medium-term), 200 (long-term institutional benchmark).

Trading rules:
  • Buy when price crosses above SMA (or when shorter SMA crosses above longer SMA).

  • Sell when price crosses below SMA.

  • Use 200 SMA as a trend filter: only take longs above it.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Window length.

Returns:

Simple moving average values. The first period - 1 entries are NaN.

Return type:

Series

ema(data, period=20)[source]

Exponential Moving Average.

Uses the standard span-based smoothing factor 2 / (period + 1). More responsive to recent price changes than SMA because it weights recent data more heavily.

Interpretation:
  • Same as SMA: price above = bullish, price below = bearish.

  • More responsive than SMA: catches trend changes faster but may produce more whipsaws.

  • EMA crossovers (e.g. 12/26 EMA) form the basis of MACD.

  • Common periods: 9 (very short-term), 21 (swing trading), 50 and 200 (institutional benchmarks).

Trading rules:
  • Same crossover rules as SMA but with faster signals.

  • In fast markets, prefer EMA over SMA for tighter stops and quicker entries.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Span for the EMA.

Returns:

Exponential moving average values.

Return type:

Series

wma(data, period=20)[source]

Weighted Moving Average.

Weights increase linearly so that the most recent observation receives the highest weight. A compromise between SMA and EMA.

Interpretation:
  • Same directional signals as SMA/EMA: price above = bullish, below = bearish, crossovers for entry/exit.

  • More responsive than SMA but less than EMA.

  • Useful when you want more weight on recent data but a smoother result than EMA.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Window length.

Returns:

Weighted moving average values.

Return type:

Series

dema(data, period=20)[source]

Double Exponential Moving Average.

DEMA = 2 * EMA(data) - EMA(EMA(data))

Reduces the lag inherent in a standard EMA by subtracting a double-smoothed version. More responsive to recent price changes.

Interpretation:
  • Same as EMA/SMA but with reduced lag. Use for faster crossover signals and tighter trailing stops.

  • Price above DEMA = bullish; below = bearish.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Span for each EMA component.

Returns:

DEMA values.

Return type:

Series

tema(data, period=20)[source]

Triple Exponential Moving Average.

TEMA = 3 * EMA - 3 * EMA(EMA) + EMA(EMA(EMA))

Even less lag than DEMA. Hugs price very tightly and reacts quickly to changes. Can overshoot in choppy markets.

Interpretation:
  • Same as EMA but with minimal lag. Excellent for short-term trend following but may whipsaw in consolidation.

  • Price above TEMA = bullish; below = bearish.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Span for each EMA component.

Returns:

TEMA values.

Return type:

Series

kama(data, period=10, fast=2, slow=30)[source]

Kaufman Adaptive Moving Average (KAMA).

KAMA adapts its smoothing constant based on the efficiency ratio of the price movement. In trending markets it acts like a fast EMA; in choppy markets it slows down to avoid whipsaws.

Interpretation:
  • Price above KAMA: Bullish.

  • Price below KAMA: Bearish.

  • Flat KAMA: Market is choppy/range-bound (KAMA stops following noise). This is the key advantage over SMA/EMA.

  • KAMA direction change: Potential trend reversal signal.

Trading rules:
  • Buy when price crosses above KAMA.

  • Sell when price crosses below KAMA.

  • KAMA’s adaptive nature makes it better for trend following than fixed-period moving averages in volatile markets.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – Efficiency ratio look-back period.

  • fast (int, default: 2) – Fast smoothing constant period.

  • slow (int, default: 30) – Slow smoothing constant period.

Returns:

KAMA values.

Return type:

Series

vwap(high, low, close, volume)[source]

Volume Weighted Average Price (VWAP).

Computed as the cumulative sum of typical_price * volume divided by cumulative volume. This is the intraday running VWAP; for session-reset VWAP, pre-group your data by session.

Interpretation:
  • Price above VWAP: Buyers are in control; longs entered at good prices relative to the average fill.

  • Price below VWAP: Sellers are in control.

  • VWAP as support/resistance: Institutional traders use VWAP as a benchmark. Price tends to gravitate toward VWAP.

  • Mean reversion: Extreme deviations from VWAP tend to revert, especially intraday.

Trading rules:
  • Buy pullbacks to VWAP in an uptrend (institutional support).

  • Sell rallies to VWAP in a downtrend (institutional resistance).

  • Institutions aim to buy below VWAP and sell above it; track whether your fills are better than VWAP.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

Cumulative VWAP values.

Return type:

Series

supertrend(high, low, close, period=10, multiplier=3.0)[source]

Supertrend indicator.

A trend-following overlay that flips between support and resistance levels based on ATR bands. One of the cleanest trend indicators.

Interpretation:
  • Direction = 1 (uptrend): Supertrend line acts as dynamic support below price. Trend is bullish.

  • Direction = -1 (downtrend): Supertrend line acts as dynamic resistance above price. Trend is bearish.

  • Flip from -1 to 1: Buy signal (trend turns bullish).

  • Flip from 1 to -1: Sell signal (trend turns bearish).

Trading rules:
  • Buy when direction flips to 1 (close above supertrend).

  • Sell when direction flips to -1 (close below supertrend).

  • Use the supertrend line as a trailing stop.

  • Higher multiplier = fewer flips but wider stops.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 10) – ATR look-back period.

  • multiplier (float, default: 3.0) – ATR multiplier for bands.

Returns:

supertrend — the indicator line, and direction (1 for uptrend / bullish, -1 for downtrend / bearish).

Return type:

dict[str, Series]

ichimoku(high, low, close, tenkan=9, kijun=26, senkou_b=52)[source]

Ichimoku Kinko Hyo (Ichimoku Cloud).

A comprehensive trend system that provides support/resistance, trend direction, and momentum in a single view.

Interpretation:
  • Price above cloud: Bullish trend. The cloud acts as support.

  • Price below cloud: Bearish trend. The cloud acts as resistance.

  • Price inside cloud: Trend is transitioning/uncertain.

  • Tenkan-Kijun cross: Tenkan crossing above Kijun = bullish signal (TK cross). Below = bearish.

  • Senkou Span A above B: Cloud is green = bullish bias.

  • Senkou Span A below B: Cloud is red = bearish bias.

  • Chikou Span above price: Confirms bullish momentum.

  • Cloud thickness: Thicker cloud = stronger support/ resistance.

Trading rules:
  • Buy when price breaks above cloud AND Tenkan > Kijun AND Chikou is above price from 26 periods ago.

  • Sell when price breaks below cloud AND Tenkan < Kijun.

  • Use cloud edges (Senkou A/B) as stop-loss levels.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tenkan (int, default: 9) – Tenkan-sen (conversion line) period.

  • kijun (int, default: 26) – Kijun-sen (base line) period.

  • senkou_b (int, default: 52) – Senkou Span B period.

Returns:

Keys: tenkan_sen, kijun_sen, senkou_span_a, senkou_span_b, chikou_span.

Return type:

dict[str, Series]

Notes

Senkou Span A and B are shifted forward by kijun periods, and the Chikou Span is shifted backward by kijun periods, matching traditional charting convention.

bollinger_bands(data, period=20, std_dev=2.0)[source]

Bollinger Bands.

A volatility-based envelope around a moving average. The bands widen during high volatility and contract during low volatility.

Interpretation:
  • Price touching upper band: Price is at the high end of its recent range. Not necessarily a sell signal in strong uptrends (walking the band).

  • Price touching lower band: Price is at the low end. Not necessarily a buy signal in downtrends.

  • Squeeze (narrow bandwidth): Low volatility – a breakout in either direction is imminent.

  • Expansion (wide bandwidth): High volatility – move may be overextended and due for consolidation.

  • %B > 1: Price is above the upper band.

  • %B < 0: Price is below the lower band.

  • %B near 0.5: Price is at the middle band (SMA).

Trading rules:
  • Mean reversion: Buy at lower band, sell at upper band (works best in ranging markets).

  • Breakout: Buy on a close above upper band with expanding bandwidth (works in trending markets).

  • Squeeze play: Wait for narrow bands, then trade the breakout direction.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – SMA window length.

  • std_dev (float, default: 2.0) – Number of standard deviations for the bands.

Returns:

upper, middle, lower, bandwidth, percent_b.

Return type:

dict[str, Series]

keltner_channel(high, low, close, period=20, multiplier=1.5)[source]

Keltner Channel.

The middle line is an EMA of the close; upper and lower bands are offset by a multiple of the Average True Range.

Interpretation:
  • Price above upper band: Strong uptrend or overbought.

  • Price below lower band: Strong downtrend or oversold.

  • Price bouncing off middle line: EMA acting as support (uptrend) or resistance (downtrend).

  • Keltner + Bollinger: When BB is inside KC, a “squeeze” is active. See squeeze_momentum().

Trading rules:
  • Buy pullbacks to the middle line (EMA) in an uptrend.

  • Sell rallies to the middle line in a downtrend.

  • Breakout above upper band = trend continuation (go long).

  • Breakout below lower band = trend continuation (go short).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – EMA / ATR period.

  • multiplier (float, default: 1.5) – ATR multiplier.

Returns:

upper, middle, lower.

Return type:

dict[str, Series]

donchian_channel(high, low, period=20)[source]

Donchian Channel.

The simplest channel indicator: the highest high and lowest low over the look-back period. The basis of the Turtle Trading system.

Interpretation:
  • Price at upper band: Price is at the highest point in period bars = potential breakout to the upside.

  • Price at lower band: Price is at the lowest point = potential breakout to the downside.

  • Channel width: Wider channel = more volatile market.

  • Middle line: Average of upper and lower = equilibrium.

Trading rules:
  • Buy when price breaks above the upper band (20-day high).

  • Sell when price breaks below the lower band (20-day low).

  • Use 10-day Donchian for exits, 20-day for entries (Turtle Trading system).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 20) – Look-back period.

Returns:

upper, lower, middle.

Return type:

dict[str, Series]

advance_decline_line(advancing, declining)[source]

Advance/Decline Line – cumulative sum of (advancing - declining).

The A/D line is a breadth indicator that tracks the running total of the difference between the number of advancing and declining issues.

Interpretation:
  • Rising A/D line with rising market: Healthy uptrend – broad participation confirms the rally.

  • Falling A/D line with rising market: Bearish divergence – fewer stocks participating in the rally. Distribution.

  • Rising A/D line with falling market: Bullish divergence – accumulation occurring beneath the surface.

  • The A/D line often leads the market at major turning points.

Parameters:
  • advancing (Series) – Number of advancing issues per period.

  • declining (Series) – Number of declining issues per period.

Returns:

Cumulative A/D line values.

Return type:

Series

Example

>>> adv = pd.Series([200, 250, 180, 300, 220])
>>> dec = pd.Series([100, 150, 220, 100, 180])
>>> advance_decline_line(adv, dec)
advance_decline_ratio(advancing, declining)[source]

Advance/Decline Ratio — advancing / declining.

Values above 1.0 indicate more advancers than decliners; below 1.0 indicates more decliners.

Parameters:
  • advancing (Series) – Number of advancing issues per period.

  • declining (Series) – Number of declining issues per period.

Returns:

A/D ratio values (NaN where declining is zero).

Return type:

Series

Example

>>> adv = pd.Series([200, 250, 180])
>>> dec = pd.Series([100, 150, 220])
>>> advance_decline_ratio(adv, dec)
mcclellan_oscillator(advancing, declining, fast=19, slow=39)[source]

McClellan Oscillator – difference between fast and slow EMA of AD diff.

McClellan = EMA(advancing - declining, fast) - EMA(advancing - declining, slow)

Interpretation:
  • Above zero: Short-term breadth momentum is positive (more stocks advancing than declining, accelerating).

  • Below zero: Short-term breadth momentum is negative.

  • Above +100: Very overbought breadth-wise.

  • Below -100: Very oversold breadth-wise.

  • Zero-line crossover: Breadth momentum shift.

  • Best used for timing entries: buy when the oscillator turns up from below -100 (oversold breadth bounce).

Parameters:
  • advancing (Series) – Number of advancing issues per period.

  • declining (Series) – Number of declining issues per period.

  • fast (int, default: 19) – Fast EMA period.

  • slow (int, default: 39) – Slow EMA period.

Returns:

McClellan Oscillator values.

Return type:

Series

Example

>>> result = mcclellan_oscillator(advancing, declining)
mcclellan_summation(advancing, declining, fast=19, slow=39)[source]

McClellan Summation Index – cumulative sum of the McClellan Oscillator.

This is the running total of the McClellan Oscillator, providing a longer-term view of market breadth.

Interpretation:
  • Rising: Long-term breadth is improving (more and more stocks participating in the advance).

  • Falling: Long-term breadth is deteriorating.

  • Above +1000: Strongly bullish long-term breadth.

  • Below -1000: Strongly bearish long-term breadth.

  • Acts as a long-term trend indicator for market internals.

Parameters:
  • advancing (Series) – Number of advancing issues per period.

  • declining (Series) – Number of declining issues per period.

  • fast (int, default: 19) – Fast EMA period for the underlying oscillator.

  • slow (int, default: 39) – Slow EMA period for the underlying oscillator.

Returns:

McClellan Summation Index values.

Return type:

Series

Example

>>> result = mcclellan_summation(advancing, declining)
arms_index(advancing_issues, declining_issues, advancing_volume, declining_volume)[source]

Arms Index (TRIN) — Short-Term Trading Index.

``TRIN = (Advancing Issues / Declining Issues) /

(Advancing Volume / Declining Volume)``

Values below 1.0 are bullish (more volume flowing into advancers); values above 1.0 are bearish.

Parameters:
  • advancing_issues (Series) – Number of advancing issues.

  • declining_issues (Series) – Number of declining issues.

  • advancing_volume (Series) – Total volume of advancing issues.

  • declining_volume (Series) – Total volume of declining issues.

Returns:

TRIN values (NaN where denominators are zero).

Return type:

Series

Example

>>> result = arms_index(adv_issues, dec_issues, adv_vol, dec_vol)
new_highs_lows(new_highs, new_lows)[source]

New Highs minus New Lows.

A simple breadth measure: positive values indicate more new highs than new lows, suggesting bullish breadth.

Parameters:
  • new_highs (Series) – Number of new highs per period.

  • new_lows (Series) – Number of new lows per period.

Returns:

New highs minus new lows.

Return type:

Series

Example

>>> nh = pd.Series([50, 60, 30])
>>> nl = pd.Series([20, 40, 50])
>>> new_highs_lows(nh, nl)
percent_above_ma(prices_df, period=50)[source]

Percentage of components above their N-period moving average.

For each row, computes how many columns have a value above their respective rolling SMA, expressed as a percentage.

Parameters:
  • prices_df (DataFrame) – DataFrame where each column is a component’s price series.

  • period (int, default: 50) – SMA look-back period.

Returns:

Percentage (0-100) of components above their SMA.

Return type:

Series

Example

>>> df = pd.DataFrame({"A": [10, 11, 12], "B": [20, 19, 18]})
>>> percent_above_ma(df, period=2)
high_low_index(new_highs, new_lows)[source]

High-Low Index — new highs as a percentage of new highs + new lows.

HLI = new_highs / (new_highs + new_lows) * 100

Values above 50 indicate more new highs; values below 50 indicate more new lows.

Parameters:
  • new_highs (Series) – Number of new highs per period.

  • new_lows (Series) – Number of new lows per period.

Returns:

High-Low Index values in [0, 100] (NaN where both are zero).

Return type:

Series

Example

>>> nh = pd.Series([50, 60, 30])
>>> nl = pd.Series([20, 40, 50])
>>> high_low_index(nh, nl)
bullish_percent(prices_df, period=50)[source]

Bullish Percent Index (simplified).

Approximates the Bullish Percent Index by computing the percentage of components trading above their period-day simple moving average. The traditional BPI uses point-and-figure buy signals, but the SMA crossover is a widely accepted simplification.

Parameters:
  • prices_df (DataFrame) – DataFrame where each column is a component’s price series.

  • period (int, default: 50) – SMA look-back period (default 50-day MA).

Returns:

Bullish Percent values in [0, 100].

Return type:

Series

Example

>>> df = pd.DataFrame({"A": [10, 11, 12], "B": [20, 19, 18]})
>>> bullish_percent(df, period=2)
cumulative_volume_index(close, volume)[source]

Cumulative Volume Index (CVI).

Adds volume on up days and subtracts volume on down days.

CVI = cumsum(sign(close.diff()) * volume)

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

CVI values.

Return type:

Series

Example

>>> close = pd.Series([100, 102, 101, 103, 104.0])
>>> volume = pd.Series([1000, 1500, 1200, 1800, 1600.0])
>>> cumulative_volume_index(close, volume)
rsi(data, period=14)[source]

Relative Strength Index (RSI).

Measures the speed and magnitude of recent price changes to evaluate overbought or oversold conditions. Uses the Wilder smoothing method (equivalent to ewm(alpha=1/period)).

RSI = 100 - (100 / (1 + RS)) where RS = avg_gain / avg_loss over period bars.

Interpretation:
  • > 70: Overbought – price may be due for a pullback. In strong uptrends, RSI can stay above 70 for extended periods.

  • 30-70: Neutral zone.

  • < 30: Oversold – price may be due for a bounce. In strong downtrends, RSI can stay below 30 for extended periods.

  • Divergence: If price makes a new high but RSI does not, bearish divergence signals weakening momentum. Conversely, bullish divergence when price makes a new low but RSI does not.

  • Centerline crossover: RSI crossing above 50 = bullish shift, below 50 = bearish shift.

Trading rules:
  • Buy when RSI crosses above 30 (oversold bounce).

  • Sell when RSI crosses below 70 (overbought reversal).

  • Use divergences for higher-probability signals.

  • Adjust thresholds in trending markets (80/20 instead of 70/30).

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – Look-back period. 14 is standard. Shorter = more sensitive, longer = smoother. Use 9 for short-term, 25 for long-term.

Returns:

RSI values in the range [0, 100].

Return type:

Series

stochastic(high, low, close, k_period=14, d_period=3)[source]

Stochastic Oscillator (%K / %D).

Measures where the close sits within the recent high-low range. When %K is near 100, price closed near the top of the range (bullish); near 0, it closed near the bottom (bearish).

Interpretation:
  • > 80: Overbought zone. In strong uptrends, the indicator can stay above 80 for extended periods without signaling a top.

  • < 20: Oversold zone. In strong downtrends, can persist.

  • %K crosses above %D below 20: Bullish crossover buy signal.

  • %K crosses below %D above 80: Bearish crossover sell signal.

  • Divergence: Price makes new high but %K does not = bearish.

Trading rules:
  • Buy when %K crosses above %D in the oversold zone (< 20).

  • Sell when %K crosses below %D in the overbought zone (> 80).

  • Avoid trading crossovers in the neutral zone (20-80) unless confirmed by other indicators.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • k_period (int, default: 14) – Look-back for %K.

  • d_period (int, default: 3) – SMA smoothing period for %D.

Returns:

k (%K) and d (%D), both in [0, 100].

Return type:

dict[str, Series]

stochastic_rsi(data, period=14, k_period=3, d_period=3)[source]

Stochastic RSI.

Applies the Stochastic formula to the RSI output, producing an even more sensitive oscillator. Useful for detecting short-term overbought/oversold conditions within the RSI itself.

Interpretation:
  • > 80: RSI is near its recent high – overbought.

  • < 20: RSI is near its recent low – oversold.

  • %K/%D crossovers: Same logic as standard Stochastic.

  • More volatile than standard Stochastic; best combined with a trend filter to avoid false signals in ranging markets.

Trading rules:
  • Buy when StochRSI crosses above 20 (oversold bounce).

  • Sell when StochRSI crosses below 80 (overbought reversal).

  • Combine with a trend indicator (e.g. 200 EMA) to filter signals in the direction of the prevailing trend.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – RSI period.

  • k_period (int, default: 3) – Smoothing for %K.

  • d_period (int, default: 3) – Smoothing for %D.

Returns:

k and d, both in [0, 100].

Return type:

dict[str, Series]

macd(data, fast=12, slow=26, signal=9)[source]

Moving Average Convergence Divergence (MACD).

Tracks the relationship between two EMAs. When the fast EMA pulls away from the slow EMA, momentum is strong. The signal line acts as a trigger for entries and exits.

Interpretation:
  • MACD above zero: Fast EMA > slow EMA = bullish momentum.

  • MACD below zero: Fast EMA < slow EMA = bearish momentum.

  • Signal line crossover: MACD crossing above its signal line is a bullish signal; crossing below is bearish.

  • Histogram: Represents the distance between MACD and signal. Growing bars = strengthening momentum. Shrinking bars = momentum fading (potential reversal ahead).

  • Divergence: Price makes a new high but MACD does not = bearish divergence. Price makes a new low but MACD does not = bullish divergence.

  • Zero-line crossover: MACD crossing above zero confirms an uptrend; crossing below confirms a downtrend.

Trading rules:
  • Buy when MACD crosses above signal line (bullish crossover).

  • Sell when MACD crosses below signal line (bearish crossover).

  • Histogram peak/trough reversals can provide early warnings.

  • Combine with price action for confirmation.

Parameters:
  • data (Series) – Price series.

  • fast (int, default: 12) – Fast EMA period.

  • slow (int, default: 26) – Slow EMA period.

  • signal (int, default: 9) – Signal EMA period.

Returns:

macd, signal, histogram.

Return type:

dict[str, Series]

williams_r(high, low, close, period=14)[source]

Williams %R.

Measures where the close is relative to the high-low range over the look-back period. Mathematically the inverse of the Stochastic %K, but on a [-100, 0] scale.

Interpretation:
  • -20 to 0: Overbought – close is near the period high.

  • -80 to -100: Oversold – close is near the period low.

  • -50 crossover: Crossing above -50 = bullish, below = bearish.

  • Note: Overbought does not mean sell immediately; in strong uptrends, Williams %R stays near 0 for extended periods.

Trading rules:
  • Buy when %R crosses above -80 (leaving oversold zone).

  • Sell when %R crosses below -20 (leaving overbought zone).

  • Use divergence between price and %R for reversal signals.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

Returns:

Williams %R values in [-100, 0].

Return type:

Series

cci(high, low, close, period=20)[source]

Commodity Channel Index (CCI).

Measures the deviation of the typical price from its moving average, normalized by mean deviation. Uses Lambert’s constant of 0.015 so that roughly 75% of values fall within [-100, +100].

Interpretation:
  • > +100: Price is unusually high relative to average – strong uptrend or overbought condition.

  • < -100: Price is unusually low – strong downtrend or oversold condition.

  • Zero-line crossover: CCI crossing above 0 indicates price is above its average (bullish); below 0 is bearish.

  • Divergence: Price makes new high but CCI does not = weakening momentum.

Trading rules:
  • Buy when CCI crosses above +100 (trend entry) or above 0 (conservative entry).

  • Sell when CCI crosses below -100 (trend entry) or below 0.

  • Exit longs when CCI crosses back below +100 from above.

  • Use +200/-200 for extreme overbought/oversold levels.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – Look-back period.

Returns:

CCI values (unbounded, typically between -300 and +300).

Return type:

Series

roc(data, period=10)[source]

Rate of Change (ROC) – percentage change over period bars.

Measures the percentage difference between the current price and the price period bars ago. A pure momentum measure.

Interpretation:
  • Positive: Price is higher than it was period bars ago.

  • Negative: Price is lower.

  • Zero-line crossover: Crossing above zero = bullish momentum shift; crossing below = bearish.

  • Extreme readings: Unusually high ROC may indicate an overextended move ripe for mean reversion.

Trading rules:
  • Buy when ROC crosses above zero from below.

  • Sell when ROC crosses below zero from above.

  • Use divergence with price for reversal signals.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – Look-back period.

Returns:

Percentage rate of change.

Return type:

Series

momentum(data, period=10)[source]

Price Momentum (difference over period bars).

The simplest momentum indicator: the absolute price change over the look-back window. Unlike ROC, this is not percentage-based, so it is scale-dependent.

Interpretation:
  • Positive: Price is rising relative to period bars ago.

  • Negative: Price is falling.

  • Zero-line crossover: Same as ROC – bullish above, bearish below.

  • Magnitude: Larger values = stronger momentum.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – Look-back period.

Returns:

Momentum values (price difference, not percentage).

Return type:

Series

tsi(data, long=25, short=13, signal=13)[source]

True Strength Index (TSI).

A double-smoothed momentum oscillator that measures the ratio of smoothed price change to smoothed absolute price change. Oscillates between -100 and +100.

Interpretation:
  • Above zero: Bullish momentum (price changes are predominantly positive).

  • Below zero: Bearish momentum.

  • Signal line crossover: TSI crossing above its signal line = bullish; crossing below = bearish.

  • Zero-line crossover: Confirms trend direction change.

  • Divergence: Price makes new high but TSI does not = bearish divergence (and vice versa).

Trading rules:
  • Buy when TSI crosses above zero or above its signal line.

  • Sell when TSI crosses below zero or below its signal line.

  • Use both zero-line and signal-line crossovers together for higher-confidence signals.

Parameters:
  • data (Series) – Price series.

  • long (int, default: 25) – Long EMA period.

  • short (int, default: 13) – Short EMA period.

  • signal (int, default: 13) – Signal line EMA period.

Returns:

tsi and signal.

Return type:

dict[str, Series]

awesome_oscillator(high, low, fast=5, slow=34)[source]

Awesome Oscillator (AO).

AO = SMA(median_price, fast) - SMA(median_price, slow)

Developed by Bill Williams. Measures market momentum using the difference between a 5-period and 34-period SMA of the midpoint price.

Interpretation:
  • Above zero: Bullish momentum (short-term average > long-term average).

  • Below zero: Bearish momentum.

  • Zero-line crossover: AO crossing above zero = buy signal; crossing below = sell signal.

  • Twin peaks (bullish): Two lows below zero where the second is higher than the first, followed by a green bar.

  • Twin peaks (bearish): Two highs above zero where the second is lower than the first, followed by a red bar.

  • Saucer: Three consecutive bars above zero where the middle bar is lowest = continuation buy signal.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • fast (int, default: 5) – Fast SMA period.

  • slow (int, default: 34) – Slow SMA period.

Returns:

AO values (unbounded, oscillates around zero).

Return type:

Series

ppo(data, fast=12, slow=26, signal=9)[source]

Percentage Price Oscillator (PPO).

Like MACD but expressed as a percentage of the slow EMA, making it comparable across different price levels and assets.

Interpretation:
  • Same signals as MACD: signal-line crossovers, zero-line crossovers, histogram analysis, and divergences.

  • Advantage over MACD: Because it is percentage-based, you can compare PPO values across stocks of different prices.

  • > 0: Fast EMA is above slow EMA = bullish.

  • < 0: Fast EMA is below slow EMA = bearish.

  • Histogram: Grows when momentum accelerates, shrinks when momentum decelerates.

Trading rules:
  • Same as MACD: buy on bullish signal crossover, sell on bearish signal crossover.

  • Use PPO instead of MACD when comparing momentum across multiple securities.

Parameters:
  • data (Series) – Price series.

  • fast (int, default: 12) – Fast EMA period.

  • slow (int, default: 26) – Slow EMA period.

  • signal (int, default: 9) – Signal EMA period.

Returns:

ppo, signal, histogram.

Return type:

dict[str, Series]

ultimate_oscillator(high, low, close, period1=7, period2=14, period3=28)[source]

Ultimate Oscillator.

Combines buying pressure across three timeframes (7, 14, 28 by default) into a single oscillator. Reduces false signals by incorporating multiple periods.

Interpretation:
  • > 70: Overbought.

  • < 30: Oversold.

  • Divergence: The primary signal. A bullish divergence occurs when price makes a new low but the UO does not, AND the UO is below 30. A bearish divergence occurs when price makes a new high but UO does not, AND UO is above 70.

Trading rules (Larry Williams’ method):
  • Buy on bullish divergence: price makes lower low, UO makes higher low, UO dips below 30, then UO breaks above the divergence high.

  • Sell when UO rises above 70, or when UO crosses below 50 after a buy signal.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period1 (int, default: 7) – First (shortest) period.

  • period2 (int, default: 14) – Second period.

  • period3 (int, default: 28) – Third (longest) period.

Returns:

Ultimate Oscillator values in [0, 100].

Return type:

Series

cmo(data, period=14)[source]

Chande Momentum Oscillator (CMO).

Similar to RSI but uses the difference between gains and losses divided by their sum, producing an oscillator in [-100, +100] instead of [0, 100].

Interpretation:
  • > +50: Strong bullish momentum, potentially overbought.

  • < -50: Strong bearish momentum, potentially oversold.

  • Zero crossover: CMO crossing above 0 = bullish; below = bearish.

  • Unlike RSI, CMO is symmetric around zero, making it easier to read directional bias.

Trading rules:
  • Buy when CMO crosses above -50 (leaving oversold).

  • Sell when CMO crosses below +50 (leaving overbought).

  • Use zero-line crossover as a trend filter.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Look-back period.

Returns:

CMO values in [-100, 100].

Return type:

Series

dpo(data, period=20)[source]

Detrended Price Oscillator (DPO).

DPO = close - SMA(close, period).shift(period // 2 + 1)

Removes the trend component from price to isolate cycles. Unlike most oscillators, DPO is not a momentum indicator – it helps identify cycle highs and lows.

Interpretation:
  • Positive: Price is above the displaced moving average (cycle high territory).

  • Negative: Price is below the displaced moving average (cycle low territory).

  • Peaks and troughs: Mark cycle turning points. Measure the time between peaks to estimate the dominant cycle length.

  • Not useful for trend trading; best for timing entries within a known cycle.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – SMA period. Should approximate the expected cycle length.

Returns:

DPO values (unbounded, oscillates around zero).

Return type:

Series

schaff_momentum(data, period=10, fast=23, slow=50)[source]

Schaff Trend Cycle applied to momentum (Schaff Momentum).

Applies two rounds of Stochastic smoothing to the difference between fast and slow EMAs, producing a bounded oscillator in [0, 100].

Interpretation:
  • > 75: Bullish – trend cycle is in the upper zone.

  • < 25: Bearish – trend cycle is in the lower zone.

  • 25-75: Transition zone.

  • Crosses above 25: Buy signal (turning bullish).

  • Crosses below 75: Sell signal (turning bearish).

  • Faster than MACD because of the double stochastic smoothing; provides earlier signals but may also have more false signals.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 10) – Stochastic look-back period.

  • fast (int, default: 23) – Fast EMA period.

  • slow (int, default: 50) – Slow EMA period.

Returns:

Schaff Momentum values in [0, 100].

Return type:

Series

Example

>>> result = schaff_momentum(close, period=10)
price_momentum_oscillator(data, short=35, long=20, signal=10)[source]

Price Momentum Oscillator (PMO) – double-smoothed ROC.

PMO = EMA(EMA(ROC(1), short), long)

Developed by Carl Swenlin, the PMO is a double-smoothed one-bar rate-of-change, scaled by a factor of 10 for visibility.

Interpretation:
  • Above zero: Bullish momentum (price trend is up).

  • Below zero: Bearish momentum.

  • Signal line crossover: PMO crossing above signal = buy; crossing below = sell.

  • Zero-line crossover: Confirms a trend change.

  • Extreme readings: PMO values at historical extremes (relative to asset) indicate overextended moves.

  • Divergence: Price makes new high but PMO does not = bearish divergence.

Trading rules:
  • Buy on bullish signal-line crossover, especially near zero or in negative territory.

  • Sell on bearish signal-line crossover.

Parameters:
  • data (Series) – Price series (typically close).

  • short (int, default: 35) – First smoothing EMA period.

  • long (int, default: 20) – Second smoothing EMA period.

  • signal (int, default: 10) – Signal line EMA period.

Returns:

pmo and signal.

Return type:

dict[str, Series]

Example

>>> result = price_momentum_oscillator(close)
>>> result["pmo"]
klinger_oscillator(high, low, close, volume, fast=34, slow=55, signal=13)[source]

Klinger Volume Oscillator – momentum-oriented view.

Uses the relationship between price trend direction and volume to predict price reversals. Combines volume with trend to identify accumulation and distribution.

Interpretation:
  • KVO above zero: Volume flow is bullish (accumulation).

  • KVO below zero: Volume flow is bearish (distribution).

  • Signal line crossover: KVO crossing above signal = buy; crossing below = sell.

  • Divergence: Price makes new high but KVO does not = distribution occurring despite rising prices.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • fast (int, default: 34) – Fast EMA period.

  • slow (int, default: 55) – Slow EMA period.

  • signal (int, default: 13) – Signal line EMA period.

Returns:

kvo and signal.

Return type:

dict[str, Series]

Example

>>> result = klinger_oscillator(high, low, close, volume)
>>> result["kvo"]
stochastic_momentum_index(high, low, close, period=14, smooth_k=3, smooth_d=3)[source]

Stochastic Momentum Index (SMI).

The SMI is a refinement of the Stochastic Oscillator that measures the distance of the close relative to the midpoint of the high-low range, double-smoothed with EMAs.

Interpretation:
  • > +40: Overbought zone.

  • < -40: Oversold zone.

  • Zero-line crossover: SMI above 0 = bullish; below = bearish.

  • Signal line crossover: SMI crossing above signal = buy; crossing below = sell.

  • More refined than Stochastic because it measures distance from the midpoint rather than from the low, reducing noise.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

  • smooth_k (int, default: 3) – First smoothing EMA period.

  • smooth_d (int, default: 3) – Signal line EMA period.

Returns:

smi and signal.

Return type:

dict[str, Series]

Example

>>> result = stochastic_momentum_index(high, low, close)
>>> result["smi"]
inertia(close, high, low, rvi_period=10, linreg_period=20)[source]

Ehlers Inertia Indicator – RVI smoothed by linear regression.

Applies a linear regression (moving regression value) to the Relative Volatility Index (RVI) to produce a momentum-like indicator.

Interpretation:
  • Above 50: Bullish – volatility conditions favor upside.

  • Below 50: Bearish – volatility conditions favor downside.

  • 50 crossover: Trend direction change signal.

  • Smoother than raw RVI due to the regression smoothing, so it gives clearer trend signals with fewer whipsaws.

Parameters:
  • close (Series) – Close prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • rvi_period (int, default: 10) – Period for computing the RVI.

  • linreg_period (int, default: 20) – Linear regression look-back period.

Returns:

Inertia values. Values above 50 are bullish; below 50 are bearish.

Return type:

Series

Example

>>> result = inertia(close, high, low)
squeeze_histogram(high, low, close, period=20, linreg_period=20)[source]

Squeeze Histogram – momentum component of the TTM Squeeze.

Computes the linear regression value of close - midline where midline is the average of the highest high and lowest low over the period, combined with the SMA.

Interpretation:
  • Positive and growing: Bullish momentum accelerating.

  • Positive and shrinking: Bullish momentum decelerating (potential top forming).

  • Negative and growing (more negative): Bearish momentum accelerating.

  • Negative and shrinking: Bearish momentum decelerating (potential bottom forming).

  • Color changes (when plotted): Dark green = accelerating bullish, light green = decelerating bullish, dark red = accelerating bearish, light red = decelerating bearish.

Trading rules:
  • Use with squeeze detection (BB inside KC). When squeeze fires (BB exits KC), trade in the direction of the histogram.

  • Buy when histogram turns positive after a squeeze release.

  • Sell when histogram turns negative after a squeeze release.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – Donchian / Bollinger look-back period.

  • linreg_period (int, default: 20) – Linear regression period for the momentum value.

Returns:

Squeeze momentum histogram values.

Return type:

Series

Example

>>> result = squeeze_histogram(high, low, close)
center_of_gravity(data, period=10)[source]

Ehlers Center of Gravity Oscillator.

A weighted sum of recent prices where more recent bars receive higher weight, normalized by a simple sum. This produces a leading oscillator.

Interpretation:
  • Oscillates around a negative value: The center of gravity shifts based on where price weight is concentrated.

  • Peaks and troughs: Mark potential turning points with virtually zero lag.

  • Leading indicator: Turns before price does, making it useful for timing entries.

  • Best used for cycle-based trading on short timeframes.

CoG = -sum(price[i] * (i+1), i=0..period-1) / sum(price[i], i=0..period-1)

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 10) – Look-back period.

Returns:

Center of Gravity values (oscillates around zero).

Return type:

Series

Example

>>> result = center_of_gravity(close, period=10)
psychological_line(data, period=12)[source]

Psychological Line — percentage of up days over N periods.

PSY = (number of up bars in period) / period * 100

Values above 50 suggest bullish sentiment; below 50 suggest bearish.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 12) – Look-back period.

Returns:

Psychological Line values in [0, 100].

Return type:

Series

Example

>>> result = psychological_line(close, period=12)
relative_performance(asset, benchmark)[source]

Relative Performance – ratio of asset to benchmark, normalized to 100.

RP = (asset / benchmark) / (asset.iloc[0] / benchmark.iloc[0]) * 100

Interpretation:
  • Rising line: Asset is outperforming the benchmark. Buy the asset, sell the benchmark (or use as a selection filter).

  • Falling line: Asset is underperforming the benchmark.

  • Above 100: Asset has outperformed since the start of the measurement period.

  • Below 100: Asset has underperformed.

  • Use to identify sector rotation and relative strength leaders.

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

Returns:

Relative performance, starting at 100.

Return type:

Series

Example

>>> asset = pd.Series([100, 105, 110])
>>> bench = pd.Series([100, 102, 104])
>>> relative_performance(asset, bench)
mansfield_rsi(asset, benchmark, period=52)[source]

Mansfield Relative Strength (not Wilder RSI).

Compares the asset/benchmark ratio to its own simple moving average, expressing the result as a percentage deviation.

MRS = ((asset / benchmark) / SMA(asset / benchmark, period) - 1) * 100

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • period (int, default: 52) – SMA look-back period.

Returns:

Mansfield RS values (percentage above/below zero line).

Return type:

Series

Example

>>> result = mansfield_rsi(asset, benchmark, period=52)
alpha(asset, benchmark, window=60, risk_free=0.0)[source]

Rolling Jensen’s Alpha vs. benchmark.

Computes alpha as the intercept of the rolling OLS regression of excess asset returns on excess benchmark returns.

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • window (int, default: 60) – Rolling window size (number of periods).

  • risk_free (float, default: 0.0) – Per-period risk-free rate.

Returns:

Rolling alpha values (annualization depends on input frequency).

Return type:

Series

Example

>>> result = alpha(asset, benchmark, window=60)
tracking_error(asset, benchmark, window=60)[source]

Rolling Tracking Error vs. benchmark.

Tracking error is the standard deviation of the difference in returns between the asset and the benchmark over a rolling window.

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • window (int, default: 60) – Rolling window size.

Returns:

Rolling tracking error values.

Return type:

Series

Example

>>> result = tracking_error(asset, benchmark, window=60)
up_down_capture(asset, benchmark)[source]

Up/Down Market Capture Ratio.

Measures how much of the benchmark’s up- and down-market returns the asset captures.

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

Returns:

up_capture, down_capture, and capture_ratio (up/down).

Return type:

dict[str, float]

Example

>>> result = up_down_capture(asset, benchmark)
>>> result["up_capture"]
drawdown(data)[source]

Drawdown from peak – current decline from running maximum.

DD = (data - running_max) / running_max

Returns non-positive values (0 at peaks, negative during drawdowns).

Interpretation:
  • 0: At or near all-time high (no drawdown).

  • -0.05 to -0.10: Mild pullback (5-10%). Normal in healthy trends.

  • -0.10 to -0.20: Correction territory. May indicate trend weakness.

  • < -0.20: Bear market territory. Significant damage to portfolio.

  • Drawdown duration (how long it stays negative) is often more painful psychologically than drawdown depth.

Parameters:

data (Series) – Price or equity curve.

Returns:

Drawdown values (non-positive fractions).

Return type:

Series

Example

>>> prices = pd.Series([100, 105, 102, 108, 103])
>>> drawdown(prices)
max_drawdown_rolling(data, window=252)[source]

Rolling maximum drawdown over a look-back window.

For each point, computes the worst drawdown experienced within the trailing window periods.

Interpretation:
  • Tracks the worst loss experienced in the recent past.

  • Deepening max drawdown: Risk is increasing.

  • Stable, shallow max drawdown: Low-risk environment.

  • Use as a risk management metric: if rolling max drawdown exceeds a threshold, reduce position size or exit.

Parameters:
  • data (Series) – Price or equity curve.

  • window (int, default: 252) – Rolling look-back window.

Returns:

Rolling max drawdown values (non-positive fractions).

Return type:

Series

Example

>>> result = max_drawdown_rolling(prices, window=60)
pain_index(data, window=252)[source]

Pain Index — mean of absolute drawdowns over a rolling window.

The Pain Index averages the magnitude of drawdowns; a higher value indicates more sustained or deeper drawdowns.

Parameters:
  • data (Series) – Price or equity curve.

  • window (int, default: 252) – Rolling look-back window.

Returns:

Pain Index values (non-negative).

Return type:

Series

Example

>>> result = pain_index(prices, window=60)
gain_loss_ratio(data, window=20)[source]

Gain/Loss Ratio — average gain / average loss over a rolling window.

Uses the per-period returns (percentage change) of the input series. Values above 1.0 indicate larger average gains than average losses.

Parameters:
  • data (Series) – Price series.

  • window (int, default: 20) – Rolling look-back window.

Returns:

Gain/loss ratio values (NaN when no losses or no gains in window).

Return type:

Series

Example

>>> result = gain_loss_ratio(prices, window=20)
profit_factor(data, window=20)[source]

Profit Factor — sum of gains / sum of losses over a rolling window.

Uses the per-period returns (percentage change) of the input series. Values above 1.0 indicate total gains exceed total losses.

Parameters:
  • data (Series) – Price series.

  • window (int, default: 20) – Rolling look-back window.

Returns:

Profit factor values (NaN when no losses in window).

Return type:

Series

Example

>>> result = profit_factor(prices, window=20)
atr(high, low, close, period=14)[source]

Average True Range (ATR).

Uses the Wilder smoothing method (ewm(alpha=1/period)). The standard measure of market volatility.

Interpretation:
  • Higher ATR: More volatile market – wider price swings.

  • Lower ATR: Less volatile – tight price action.

  • Rising ATR: Volatility is increasing (often at trend beginnings or during strong moves).

  • Falling ATR: Volatility is decreasing (often during consolidation, before a breakout).

  • ATR does not indicate direction, only the magnitude of price movement.

Trading rules:
  • Stop placement: Set stop-loss at 2x or 3x ATR from entry to account for normal market noise.

  • Position sizing: Risk a fixed dollar amount per trade; divide by ATR to determine share count.

  • Breakout confirmation: A breakout with rising ATR is more likely to sustain than one with falling ATR.

  • Trailing stop: Trail by 2-3x ATR below the highest high (for longs).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Smoothing period.

Returns:

ATR values (always >= 0).

Return type:

Series

true_range(high, low, close)[source]

True Range.

TR = max(H - L, |H - C_prev|, |L - C_prev|)

The single-bar volatility measure that accounts for gaps.

Interpretation:
  • High TR: Large price movement – high volatility bar.

  • Low TR: Small price movement – low volatility bar.

  • Spikes in TR often occur at trend changes or breakouts.

  • TR forms the basis of ATR and many other volatility indicators.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

Returns:

True Range values (always >= 0).

Return type:

Series

natr(high, low, close, period=14)[source]

Normalized Average True Range (NATR).

NATR = (ATR / close) * 100

Interpretation:
  • Same as ATR but expressed as a percentage of price, making it comparable across different assets and price levels.

  • Higher NATR: More volatile (in percentage terms).

  • Lower NATR: Less volatile.

  • Useful for ranking assets by volatility or for building volatility-weighted portfolios.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – ATR period.

Returns:

NATR as a percentage.

Return type:

Series

bbwidth(data, period=20, std_dev=2.0)[source]

Bollinger Band Width.

BBWidth = (upper - lower) / middle

Interpretation:
  • Low BBWidth (squeeze): Bollinger Bands are narrow – volatility is low. A breakout is imminent. This is the key signal: low volatility precedes high volatility.

  • High BBWidth: Bollinger Bands are wide – volatility is high. The move may be overextended.

  • BBWidth at 6-month low: Strong squeeze – prepare for a significant breakout.

  • BBWidth expanding: Breakout in progress.

Trading rules:
  • Look for BBWidth at historical lows (squeeze).

  • When the squeeze releases (BBWidth starts expanding), trade the breakout direction.

  • Combine with momentum indicators to determine direction.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – SMA period.

  • std_dev (float, default: 2.0) – Number of standard deviations.

Returns:

Bandwidth values.

Return type:

Series

kc_width(high, low, close, period=20, multiplier=1.5)[source]

Keltner Channel Width.

KC_Width = (upper - lower) / middle

Interpretation:
  • Same concept as BBWidth but based on ATR instead of standard deviation.

  • Narrow KC Width: Low ATR volatility, potential squeeze.

  • Wide KC Width: High ATR volatility, extended move.

  • Used with BBWidth for the TTM Squeeze: when BB is inside KC, a squeeze is active.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – EMA / ATR period.

  • multiplier (float, default: 1.5) – ATR multiplier.

Returns:

Keltner Channel width values.

Return type:

Series

chaikin_volatility(high, low, period=10, smoothing=10)[source]

Chaikin Volatility.

Measures the rate of change of the EMA of the high-low spread.

Interpretation:
  • Rising: Volatility is increasing (range is expanding).

  • Falling: Volatility is decreasing (range is contracting).

  • Spike up: Can indicate a market top (panic/climax).

  • Spike down: Can indicate a market bottom (capitulation followed by quiet).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 10) – EMA smoothing period for the H-L spread.

  • smoothing (int, default: 10) – ROC period applied to the smoothed spread.

Returns:

Chaikin Volatility as a percentage.

Return type:

Series

historical_volatility(data, period=21, annualize=True)[source]

Historical Volatility (close-to-close).

Computes the rolling standard deviation of log returns. When annualize is True the result is scaled by sqrt(252).

Interpretation:
  • High HV (e.g. > 30% annualized for equities): Asset is highly volatile. Wider stops and smaller positions needed.

  • Low HV (e.g. < 15% annualized): Asset is calm. Tighter stops and larger positions possible.

  • HV vs Implied Volatility: If HV < IV, options are relatively expensive (sell premium). If HV > IV, options are cheap (buy premium).

  • Rising HV: Uncertainty increasing. Often accompanies selloffs.

  • Falling HV: Market calming down. Often accompanies gradual rallies.

Parameters:
  • data (Series) – Price series (close).

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

Returns:

Historical volatility (annualized if requested).

Return type:

Series

mass_index(high, low, period=9, trigger=25)[source]

Mass Index.

The Mass Index uses the high-low range to identify trend reversals based on range expansions. It accumulates the ratio of two EMAs of the range over the trigger period.

Interpretation:
  • Reversal bulge: The key signal. When Mass Index rises above 27 and then falls back below 26.5, a trend reversal is likely (regardless of direction).

  • The indicator does not tell you the direction of the reversal, only that one is coming.

  • Combine with a trend indicator to determine which direction the reversal will take.

Trading rules:
  • When Mass Index crosses above 27 then back below 26.5 (reversal bulge), prepare for a trend change.

  • Use a 9-period EMA crossover or similar to determine the new trend direction.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 9) – EMA period for the range.

  • trigger (int, default: 25) – Summation (rolling sum) window.

Returns:

Mass Index values. A reversal bulge occurs when the index rises above 27 and then falls below 26.5.

Return type:

Series

garman_klass(high, low, close, open_, period=21, annualize=True)[source]

Garman-Klass volatility estimator.

An efficient OHLC volatility estimator that uses open, high, low, and close prices. More efficient than close-to-close because it uses intraday range information.

Interpretation:
  • Values are directly comparable to historical volatility.

  • Higher efficiency: Uses the same data as close-to-close but extracts more information, producing tighter estimates.

  • Compare with Parkinson and Yang-Zhang to assess which estimator best suits your data.

  • Does not handle overnight gaps well; use Yang-Zhang for assets with significant overnight risk.

GK = sqrt((1/n) * sum(0.5*(ln(H/L))^2 - (2*ln(2)-1)*(ln(C/O))^2))

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open (pd.Series) – Open prices.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

  • open_ (Series)

Returns:

Garman-Klass volatility estimate.

Return type:

Series

Example

>>> gk = garman_klass(high, low, close, open_, period=21)
Parameters:
Return type:

Series

parkinson(high, low, period=21, annualize=True)[source]

Parkinson volatility estimator.

Uses the high-low range to estimate volatility, which is more efficient than close-to-close since it captures intraday extremes.

Interpretation:
  • Approximately 5x more efficient than close-to-close.

  • Tends to underestimate true volatility when there are overnight gaps (since it ignores open/close).

  • Best suited for assets that trade continuously (e.g. forex).

Parkinson = sqrt((1 / (4 * n * ln(2))) * sum((ln(H/L))^2))

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

Returns:

Parkinson volatility estimate.

Return type:

Series

Example

>>> pk = parkinson(high, low, period=21)
rogers_satchell(high, low, close, open_, period=21, annualize=True)[source]

Rogers-Satchell volatility estimator.

Accounts for non-zero drift (trending markets), making it more robust than Parkinson or Garman-Klass for trending assets.

Interpretation:
  • Better than Garman-Klass for assets with strong trends, because it does not assume zero drift.

  • Still does not handle overnight gaps; for that, use Yang-Zhang.

RS = sqrt((1/n) * sum(ln(H/C)*ln(H/O) + ln(L/C)*ln(L/O)))

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open (pd.Series) – Open prices.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

  • open_ (Series)

Returns:

Rogers-Satchell volatility estimate.

Return type:

Series

Example

>>> rs = rogers_satchell(high, low, close, open_, period=21)
Parameters:
Return type:

Series

yang_zhang(high, low, close, open_, period=21, annualize=True)[source]

Yang-Zhang volatility estimator.

The most efficient OHLC volatility estimator. Combines overnight (close-to-open) volatility, open-to-close volatility, and the Rogers-Satchell estimator.

Interpretation:
  • The gold standard for OHLC volatility estimation.

  • Handles both overnight gaps and intraday drift.

  • Use this as the default volatility estimator when you have full OHLC data.

  • Compare with close-to-close: if Yang-Zhang is significantly higher, overnight/gap risk is material.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open (pd.Series) – Open prices.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

  • open_ (Series)

Returns:

Yang-Zhang volatility estimate.

Return type:

Series

Example

>>> yz = yang_zhang(high, low, close, open_, period=21)
Parameters:
Return type:

Series

close_to_close(data, period=21, annualize=True)[source]

Close-to-close volatility (standard deviation of log returns).

The simplest volatility estimator based on daily log returns. This is equivalent to historical_volatility() but named explicitly to distinguish it from range-based estimators.

Interpretation:
  • The baseline volatility measure. All other estimators (Parkinson, Garman-Klass, Yang-Zhang) should be compared against this.

  • See historical_volatility() for full interpretation.

Parameters:
  • data (Series) – Close price series.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

Returns:

Close-to-close volatility.

Return type:

Series

Example

>>> cc = close_to_close(close, period=21)
ulcer_index(data, period=14)[source]

Ulcer Index.

Measures downside volatility by computing the quadratic mean of percentage drawdowns from the rolling maximum over the given period. Higher values indicate greater drawdown depth and duration.

Interpretation:
  • Low values (< 5): Stable asset with shallow drawdowns.

  • High values (> 10): Asset is experiencing significant drawdowns.

  • Unlike standard deviation, only measures downside risk.

  • Used in the Martin Ratio (return / Ulcer Index) as a risk-adjusted performance metric.

  • Rising Ulcer Index = drawdowns are deepening = trouble.

UI = sqrt(mean(R^2)) where R = 100 * (C - max(C, n)) / max(C, n)

Parameters:
  • data (Series) – Close price series.

  • period (int, default: 14) – Rolling window.

Returns:

Ulcer Index values (always >= 0).

Return type:

Series

Example

>>> ui = ulcer_index(close, period=14)
relative_volatility_index(data, period=10, smoothing=14)[source]

Relative Volatility Index (RVI).

Applies the RSI formula to the rolling standard deviation of closes rather than to price changes.

Interpretation:
  • > 50: Volatility is increasing (standard deviation is rising) – directional moves are more likely.

  • < 50: Volatility is decreasing (standard deviation is falling) – consolidation / range-bound.

  • Not a standalone indicator; best used as a filter.

Trading rules:
  • Confirm RSI signals: only take RSI buy signals when RVI > 50.

  • Avoid breakout trades when RVI < 50 (low volatility = false breakout risk).

Parameters:
  • data (Series) – Close price series.

  • period (int, default: 10) – Standard deviation lookback.

  • smoothing (int, default: 14) – RSI-style smoothing period applied to the std-dev changes.

Returns:

RVI values oscillating between 0 and 100.

Return type:

Series

Example

>>> rvi = relative_volatility_index(close, period=10, smoothing=14)
acceleration_bands(high, low, close, period=20, factor=0.001)[source]

Acceleration Bands.

Bands that widen with high-low range acceleration, narrowing during consolidation. Uses factor * (high - low) / (high + low) as the width multiplier.

Interpretation:
  • Price above upper band: Strong uptrend / breakout.

  • Price below lower band: Strong downtrend / breakdown.

  • Bands narrowing: Consolidation – breakout imminent.

  • Bands widening: Trend accelerating.

  • Similar concept to Bollinger Bands but based on range acceleration rather than standard deviation.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – SMA period.

  • factor (float, default: 0.001) – Width factor applied to range acceleration.

Returns:

Dictionary with keys "upper", "middle", "lower".

Return type:

dict[str, Series]

Example

>>> bands = acceleration_bands(high, low, close, period=20)
>>> upper = bands["upper"]
standard_deviation(data, period=20)[source]

Rolling standard deviation.

Computes the rolling sample standard deviation over the given period.

Interpretation:
  • Rising: Volatility increasing – larger price swings.

  • Falling: Volatility decreasing – tighter price action.

  • Low standard deviation often precedes a breakout.

  • Used to compute Bollinger Bands (middle +/- N * std_dev).

Parameters:
  • data (Series) – Input price series.

  • period (int, default: 20) – Rolling window.

Returns:

Rolling standard deviation values.

Return type:

Series

Example

>>> sd = standard_deviation(close, period=20)
variance(data, period=20)[source]

Rolling variance.

Computes the rolling sample variance over the given period.

Interpretation:
  • The square of standard deviation. Same directional interpretation as standard deviation.

  • Useful in mathematical contexts where variance is preferred (e.g. portfolio optimization, risk decomposition).

Parameters:
  • data (Series) – Input price series.

  • period (int, default: 20) – Rolling window.

Returns:

Rolling variance values.

Return type:

Series

Example

>>> v = variance(close, period=20)
obv(close, volume)[source]

On Balance Volume (OBV).

OBV is a cumulative running total of volume. Volume is added on up-close days and subtracted on down-close days.

Interpretation:
  • Rising OBV: Volume is flowing in (accumulation) – bullish.

  • Falling OBV: Volume is flowing out (distribution) – bearish.

  • Divergence: The most important signal. Price makes a new high but OBV does not = smart money is not confirming the move (bearish divergence). Price makes a new low but OBV does not = accumulation is occurring (bullish divergence).

  • Breakout confirmation: OBV breaking to a new high alongside price confirms the breakout is genuine.

Trading rules:
  • Buy when OBV diverges bullishly from price (price falls, OBV holds or rises).

  • Sell when OBV diverges bearishly from price (price rises, OBV flattens or falls).

  • Use OBV trend (rising/falling) to confirm price trends.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

OBV values.

Return type:

Series

ad_line(high, low, close, volume)[source]

Accumulation/Distribution Line (AD Line).

Uses the Close Location Value (CLV) money flow multiplier.

Interpretation:
  • Rising AD line: Accumulation – buying pressure dominates. Volume is flowing into the asset.

  • Falling AD line: Distribution – selling pressure dominates.

  • Divergence: Price makes new high but AD does not = distribution despite rising prices (bearish). Price makes new low but AD does not = accumulation (bullish).

  • Unlike OBV, the AD line considers where the close is within the high-low range, not just the direction of the close.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

Cumulative A/D line values.

Return type:

Series

cmf(high, low, close, volume, period=20)[source]

Chaikin Money Flow (CMF).

Measures money flow volume over a rolling period, showing whether buying or selling pressure is dominant.

Interpretation:
  • Positive (> 0): Buying pressure (accumulation). The higher the value, the stronger the buying.

  • Negative (< 0): Selling pressure (distribution).

  • > +0.25: Strong buying pressure.

  • < -0.25: Strong selling pressure.

  • Zero-line crossover: Shift from accumulation to distribution or vice versa.

  • Divergence: Price makes new high but CMF is falling = distribution.

Trading rules:
  • Buy when CMF crosses above zero (accumulation starting).

  • Sell when CMF crosses below zero (distribution starting).

  • Confirm breakouts: price breaking resistance with positive CMF is more reliable.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 20) – Look-back period.

Returns:

CMF values in [-1, 1].

Return type:

Series

mfi(high, low, close, volume, period=14)[source]

Money Flow Index (MFI).

Often called the volume-weighted RSI. Incorporates both price and volume to identify overbought/oversold conditions.

Interpretation:
  • > 80: Overbought – high buying pressure, potential reversal.

  • < 20: Oversold – high selling pressure, potential bounce.

  • Divergence: Price makes new high but MFI does not = weakening volume-confirmed momentum (bearish).

  • More reliable than RSI alone because it includes volume: a price move on heavy volume is more meaningful.

Trading rules:
  • Buy when MFI crosses above 20 (leaving oversold).

  • Sell when MFI crosses below 80 (leaving overbought).

  • MFI divergence with price is a strong reversal signal.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 14) – Look-back period.

Returns:

MFI values in [0, 100].

Return type:

Series

eom(high, low, volume, period=14)[source]

Ease of Movement (EMV / EOM).

Relates price change to volume, showing how easily price is moving.

Interpretation:
  • Positive: Price is advancing on relatively low volume (easy movement up) = bullish.

  • Negative: Price is declining on relatively low volume (easy movement down) = bearish.

  • Near zero: Price movement requires substantial volume = indecision or strong resistance/support.

  • Zero-line crossover: Shift from easy upward to easy downward movement or vice versa.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • volume (Series) – Volume data.

  • period (int, default: 14) – Smoothing period.

Returns:

EOM values (smoothed).

Return type:

Series

force_index(close, volume, period=13)[source]

Force Index.

Force = close.diff() * volume, then smoothed with EMA.

Combines price change and volume to measure the strength behind a move.

Interpretation:
  • Positive: Buying force – price is rising with volume.

  • Negative: Selling force – price is falling with volume.

  • Magnitude: Larger values = stronger force behind the move.

  • Zero-line crossover: Shift from buying to selling force.

  • Divergence: Price makes new high but Force Index is declining = momentum weakening.

Trading rules:
  • Buy when Force Index crosses above zero in an uptrend (pullback entry).

  • Sell when Force Index crosses below zero in a downtrend.

  • Use short period (2) for entries, longer period (13) for trend confirmation.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 13) – EMA smoothing period.

Returns:

Smoothed Force Index.

Return type:

Series

nvi(close, volume)[source]

Negative Volume Index (NVI).

NVI focuses on days when volume decreases; the assumption is that smart money is active on low-volume days.

Interpretation:
  • Rising NVI: Smart money is buying on quiet days.

  • Falling NVI: Smart money is selling on quiet days.

  • NVI above its 255-day MA: Bull market (historically correct ~96% of the time according to Norman Fosback).

  • NVI below its 255-day MA: Bear market.

  • Compare with PVI to distinguish smart vs. crowd behavior.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

NVI values (starts at 1000).

Return type:

Series

pvi(close, volume)[source]

Positive Volume Index (PVI).

PVI focuses on days when volume increases; the assumption is that the crowd follows price on high-volume days.

Interpretation:
  • Rising PVI: The crowd is buying on high-volume days.

  • Falling PVI: The crowd is selling on high-volume days.

  • PVI below its 255-day MA: Bearish sign (the crowd is pushing prices down on active days).

  • PVI tends to track what the public/retail traders are doing; NVI tracks institutional/smart money behavior.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

PVI values (starts at 1000).

Return type:

Series

vpt(close, volume)[source]

Volume Price Trend (VPT).

VPT = cumsum(volume * pct_change(close))

Interpretation:
  • Rising VPT: Volume is confirming the price trend (bullish).

  • Falling VPT: Volume is working against the price trend.

  • Divergence: Price rises but VPT falls = distribution.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

VPT values.

Return type:

Series

adosc(high, low, close, volume, fast=3, slow=10)[source]

Accumulation/Distribution Oscillator (Chaikin Oscillator).

ADOSC = EMA(AD, fast) - EMA(AD, slow)

Interpretation:
  • Positive: Short-term accumulation exceeds long-term = money is flowing in.

  • Negative: Short-term distribution exceeds long-term = money is flowing out.

  • Zero-line crossover: Buy when crossing above zero, sell when crossing below.

  • Divergence: Price makes new high but oscillator falls = distribution.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • fast (int, default: 3) – Fast EMA period.

  • slow (int, default: 10) – Slow EMA period.

Returns:

Chaikin Oscillator values.

Return type:

Series

adx(high, low, close, period=14)[source]

Average Directional Index (ADX) with +DI and -DI.

Measures the strength of a trend regardless of its direction. +DI and -DI show the direction.

Interpretation:
  • ADX > 25: Trend is strong enough to trade.

  • ADX > 50: Very strong trend.

  • ADX < 20: No trend (range-bound / choppy).

  • ADX rising: Trend is strengthening.

  • ADX falling: Trend is weakening (not necessarily reversing).

  • +DI > -DI: Uptrend (buyers dominate).

  • -DI > +DI: Downtrend (sellers dominate).

  • +DI/-DI crossover: Trend direction change.

Trading rules:
  • Buy when +DI crosses above -DI AND ADX > 25 (trending up).

  • Sell when -DI crosses above +DI AND ADX > 25 (trending down).

  • Avoid trading when ADX < 20 (no trend).

  • Use ADX as a filter: only apply trend-following strategies when ADX > 25; use mean-reversion when ADX < 20.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Smoothing period.

Returns:

adx, plus_di, minus_di — all in [0, 100].

Return type:

dict[str, Series]

aroon(high, low, period=25)[source]

Aroon Indicator.

Measures the time since the last high/low to identify trend direction and strength.

Interpretation:
  • Aroon Up > 70: Strong uptrend (recent new highs).

  • Aroon Down > 70: Strong downtrend (recent new lows).

  • Aroon Up < 30: Weak uptrend (no recent new highs).

  • Aroon Down < 30: Weak downtrend (no recent new lows).

  • Aroon Up crosses above Aroon Down: New uptrend starting.

  • Aroon Down crosses above Aroon Up: New downtrend starting.

  • Both below 50: Consolidation / no trend.

  • Oscillator: Positive = uptrend, negative = downtrend.

Trading rules:
  • Buy when Aroon Up crosses above Aroon Down.

  • Sell when Aroon Down crosses above Aroon Up.

  • Strongest signal when one Aroon is above 70 and the other is below 30.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 25) – Look-back period.

Returns:

aroon_up, aroon_down, oscillator — up/down in [0, 100], oscillator in [-100, 100].

Return type:

dict[str, Series]

psar(high, low, close, af_start=0.02, af_step=0.02, af_max=0.2)[source]

Parabolic SAR (Stop and Reverse).

A trend-following indicator that provides entry/exit points and trailing stop levels.

Interpretation:
  • SAR dots below price: Uptrend. The SAR value is a trailing stop / support level.

  • SAR dots above price: Downtrend. The SAR value is a trailing stop / resistance level.

  • SAR flip (below to above): Sell signal – trend has reversed from bullish to bearish.

  • SAR flip (above to below): Buy signal – trend has reversed from bearish to bullish.

Trading rules:
  • Buy when SAR flips below price (dots move under candles).

  • Sell when SAR flips above price (dots move above candles).

  • Use SAR values as trailing stop-loss levels.

  • Works best in trending markets; generates many false signals in ranging markets. Combine with ADX to filter.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • af_start (float, default: 0.02) – Initial acceleration factor.

  • af_step (float, default: 0.02) – Acceleration factor increment.

  • af_max (float, default: 0.2) – Maximum acceleration factor.

Returns:

Parabolic SAR values. Values above price indicate downtrend; values below price indicate uptrend.

Return type:

Series

vortex(high, low, close, period=14)[source]

Vortex Indicator.

Captures positive and negative trend movement by comparing the distance between current high/low and previous low/high.

Interpretation:
  • +VI > -VI: Uptrend – positive vortex movement dominates.

  • -VI > +VI: Downtrend – negative vortex movement dominates.

  • +VI crosses above -VI: Bullish trend change signal.

  • -VI crosses above +VI: Bearish trend change signal.

  • Both near 1.0: Trend is neutral or transitioning.

Trading rules:
  • Buy when +VI crosses above -VI.

  • Sell when -VI crosses above +VI.

  • Use a threshold (e.g. 1.1) to filter weak crossovers.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

Returns:

plus_vi and minus_vi.

Return type:

dict[str, Series]

trix(data, period=15)[source]

TRIX – Triple-smoothed EMA rate of change.

TRIX = 100 * ROC(EMA(EMA(EMA(data))))

Filters out insignificant price movements by triple-smoothing before computing the rate of change.

Interpretation:
  • Above zero: Bullish momentum (triple-smoothed trend up).

  • Below zero: Bearish momentum.

  • Zero-line crossover: Buy signal when crossing above zero; sell when crossing below.

  • Signal line: Often paired with a signal EMA for crossover signals.

  • Extremely smooth; good for identifying major trend changes but lags significantly.

Trading rules:
  • Buy when TRIX crosses above zero.

  • Sell when TRIX crosses below zero.

  • Use for long-term trend identification, not short-term timing.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 15) – EMA period for each smoothing pass.

Returns:

TRIX values.

Return type:

Series

linear_regression(data, period=14)[source]

Rolling Linear Regression.

Fits an OLS regression line to the last period values at each bar.

Interpretation:
  • Positive slope: Price trend is up over the window.

  • Negative slope: Price trend is down.

  • R-squared near 1: Price is moving in a clean line (strong trend with low noise).

  • R-squared near 0: No linear trend (choppy/range-bound).

  • Value: The regression endpoint acts as a smoothed trend line with less lag than a moving average.

Trading rules:
  • Trade in the direction of the slope when R-squared > 0.5.

  • Avoid trend-following trades when R-squared < 0.2.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Look-back window.

Returns:

value (end-of-line prediction), slope, intercept, r_squared.

Return type:

dict[str, Series]

linear_regression_slope(data, period=14)[source]

Rolling Linear Regression Slope.

A convenience wrapper around linear_regression() that returns only the slope component.

Interpretation:
  • Positive: Uptrend over the look-back period.

  • Negative: Downtrend.

  • Magnitude: Steeper slope = stronger trend.

  • Zero crossover: Trend direction change.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Look-back window.

Returns:

Slope values.

Return type:

Series

zigzag(close, pct_change=5.0)[source]

ZigZag indicator – connects swing highs and lows.

Identifies pivots where price reverses by at least pct_change percent, then linearly interpolates between them.

Interpretation:
  • Filters out noise to reveal the true swing structure of price.

  • Not a trading signal: The last segment repaints as new data arrives. Use only for historical analysis.

  • Swing counting: Measure the distance between pivots for wave analysis (Elliott Wave, harmonic patterns).

  • Support/resistance: Pivot levels often act as future S/R.

  • Useful for backtesting swing-trading strategies.

Parameters:
  • close (Series) – Close prices.

  • pct_change (float, default: 5.0) – Minimum percentage change to register a new pivot.

Returns:

ZigZag line (interpolated between pivots). Non-pivot bars are filled via linear interpolation; leading/trailing NaNs remain where no pivot has been established.

Return type:

Series

Example

>>> import pandas as pd
>>> zz = zigzag(pd.Series([100, 110, 105, 95, 100, 90]), pct_change=5.0)
heikin_ashi(open_, high, low, close)[source]

Heikin-Ashi modified OHLC candles.

Modified candlesticks that smooth price action and make trends easier to identify.

Interpretation:
  • Green HA candles with no lower shadow: Strong uptrend.

  • Red HA candles with no upper shadow: Strong downtrend.

  • Small body with long shadows: Indecision / potential reversal.

  • Color change: Possible trend reversal (green to red or vice versa).

  • HA candles smooth noise, making it easier to stay in trends and avoid premature exits.

Trading rules:
  • Stay long as long as HA candles remain green.

  • Stay short as long as HA candles remain red.

  • Watch for doji-like HA candles as reversal warnings.

  • Note: HA prices are synthetic – do not use them for actual order placement. Use regular prices for entries/exits.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

ha_open, ha_high, ha_low, ha_close.

Return type:

dict[str, Series]

Example

>>> import pandas as pd
>>> ha = heikin_ashi(
...     pd.Series([100, 102]),
...     pd.Series([105, 106]),
...     pd.Series([99, 101]),
...     pd.Series([104, 103]),
... )
Parameters:
Return type:

dict[str, Series]

mcginley_dynamic(data, period=14)[source]

McGinley Dynamic – adaptive moving average.

Adjusts its speed based on market velocity, reducing whipsaws compared to a standard EMA.

Interpretation:
  • Price above McGinley: Bullish trend.

  • Price below McGinley: Bearish trend.

  • Automatically speeds up in fast markets and slows down in slow markets, reducing false crossovers.

  • Acts as a more reliable dynamic support/resistance than traditional moving averages.

MD_t = MD_{t-1} + (price - MD_{t-1}) / (N * (price / MD_{t-1})^4)

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – Smoothing period.

Returns:

McGinley Dynamic values.

Return type:

Series

Example

>>> import pandas as pd
>>> md = mcginley_dynamic(pd.Series([100, 102, 101, 103, 105]))
schaff_trend_cycle(close, period=10, fast=23, slow=50)[source]

Schaff Trend Cycle – MACD passed through a double stochastic.

Combines the MACD histogram with stochastic smoothing for a faster, smoother oscillator bounded between 0 and 100.

Interpretation:
  • > 75: Bullish trend established.

  • < 25: Bearish trend established.

  • Crosses above 25: Buy signal (bearish-to-bullish shift).

  • Crosses below 75: Sell signal (bullish-to-bearish shift).

  • Faster than MACD because of the double stochastic processing.

  • Spends most of its time at extremes (near 0 or 100), with quick transitions between them.

Parameters:
  • close (Series) – Close prices.

  • period (int, default: 10) – Stochastic look-back period.

  • fast (int, default: 23) – Fast EMA period for MACD.

  • slow (int, default: 50) – Slow EMA period for MACD.

Returns:

STC values in [0, 100].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> stc = schaff_trend_cycle(pd.Series(np.random.randn(100).cumsum() + 100))
guppy_mma(data)[source]

Guppy Multiple Moving Average (GMMA).

Developed by Daryl Guppy. Uses two groups of EMAs to visualize the behavior of both traders (short-term) and investors (long-term).

Interpretation:
  • Short-term group fanning out above long-term group: Strong uptrend with trader and investor agreement.

  • Short-term group fanning out below long-term group: Strong downtrend.

  • Groups compressing: Trend weakening, consolidation.

  • Short-term crossing long-term: Trend change signal.

  • Wide separation between groups: Strong conviction.

  • Groups intertwined/overlapping: Indecision, no trend.

Returns two groups of EMAs:

  • Short-term group: 3, 5, 8, 10, 12, 15

  • Long-term group: 30, 35, 40, 45, 50, 60

Parameters:

data (Series) – Price series (typically close).

Returns:

Keys short_3, short_5, …, short_15, long_30, long_35, …, long_60.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> g = guppy_mma(pd.Series(np.random.randn(100).cumsum() + 100))
rainbow_ma(data, period=10, levels=10)[source]

Rainbow Moving Average – recursive SMAs.

Each level is an SMA of the previous level. Level 1 is SMA of data, level 2 is SMA of level 1, and so on.

Interpretation:
  • Price above all bands: Strong uptrend.

  • Price below all bands: Strong downtrend.

  • Bands fanning out: Trend strengthening.

  • Bands compressing: Trend weakening or consolidation.

  • Price touching inner bands then bouncing: Pullback buy/sell opportunity in the direction of the trend.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – SMA period applied at each level.

  • levels (int, default: 10) – Number of SMA recursions (typically 10).

Returns:

Keys sma_1 through sma_{levels}.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> rb = rainbow_ma(pd.Series(np.random.randn(100).cumsum() + 100))
hull_ma(data, period=16)[source]

Hull Moving Average (HMA).

HMA = WMA(2 * WMA(n/2) - WMA(n), sqrt(n))

Provides a fast, smooth moving average with reduced lag.

Interpretation:
  • Price above HMA: Bullish.

  • Price below HMA: Bearish.

  • HMA slope change: Early trend change signal. HMA turning up = bullish; turning down = bearish.

  • Extremely responsive due to the sqrt(n) final smoothing; excellent for short-term trend following.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 16) – HMA period.

Returns:

Hull Moving Average values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> hma = hull_ma(pd.Series(np.random.randn(100).cumsum() + 100), period=16)
zero_lag_ema(data, period=21)[source]

Zero-Lag Exponential Moving Average (ZLEMA).

Compensates for inherent EMA lag by applying the EMA to a de-lagged series: zlema_input = data + (data - data.shift(lag)) where lag = (period - 1) / 2.

Interpretation:
  • Same signals as EMA but with near-zero lag.

  • More responsive to recent price changes, giving earlier crossover signals.

  • Can overshoot in choppy markets due to the de-lagging adjustment.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 21) – EMA period.

Returns:

ZLEMA values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> zl = zero_lag_ema(pd.Series(np.random.randn(100).cumsum() + 100))
vidya(data, period=14, smooth=5)[source]

Variable Index Dynamic Average (VIDYA).

Uses the Chande Momentum Oscillator (CMO) as a volatility index to dynamically adjust the smoothing constant of an EMA.

Interpretation:
  • Behaves like a fast EMA in trending markets (high CMO) and a slow EMA in ranging markets (low CMO).

  • Price above VIDYA: Bullish trend.

  • Price below VIDYA: Bearish trend.

  • Less prone to whipsaws than standard EMA in choppy markets.

VIDYA_t = alpha * |CMO_t| * price_t + (1 - alpha * |CMO_t|) * VIDYA_{t-1}

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – CMO look-back period.

  • smooth (int, default: 5) – Smoothing period to derive the base alpha (2 / (smooth + 1)).

Returns:

VIDYA values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> v = vidya(pd.Series(np.random.randn(100).cumsum() + 100))
tilson_t3(data, period=5, volume_factor=0.7)[source]

Tilson T3 – triple-smoothed exponential moving average.

Applies six sequential EMAs with Tilson coefficients derived from the volume_factor to produce an ultra-smooth, low-lag average.

Interpretation:
  • Extremely smooth trend line with less lag than TEMA.

  • Price above T3: Bullish.

  • Price below T3: Bearish.

  • T3 slope change: Very reliable trend change signal due to the heavy smoothing.

  • Best for medium to long-term trend identification.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 5) – EMA period for each pass.

  • volume_factor (float, default: 0.7) – Volume factor (commonly 0.7). Controls the overshoot reduction.

Returns:

Tilson T3 values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> t3 = tilson_t3(pd.Series(np.random.randn(100).cumsum() + 100))
fractal_adaptive_ma(data, period=16)[source]

Fractal Adaptive Moving Average (FRAMA).

Uses the fractal dimension of the price series to dynamically adjust the EMA smoothing factor. More responsive in trending markets and slower during consolidation.

Interpretation:
  • Price above FRAMA: Bullish trend.

  • Price below FRAMA: Bearish trend.

  • Adapts automatically: becomes responsive (like short EMA) in trending markets and sluggish (like long EMA) during consolidation.

  • Excellent for trend following with automatic noise filtering.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 16) – Look-back period (should be even; if odd, it is rounded up).

Returns:

FRAMA values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> f = fractal_adaptive_ma(pd.Series(np.random.randn(200).cumsum() + 100))
candle_body_size(open_, close)[source]

Absolute candle body size.

Computed as abs(close - open).

Interpretation:
  • Large body: Strong conviction – one side dominated.

  • Small body: Indecision or low activity.

  • Compare to average body size to identify unusual bars.

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Absolute body size for each bar.

Example

>>> body = candle_body_size(open_, close)
Parameters:
Return type:

Series

candle_range(high, low)[source]

Full candle range (high minus low).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

Return type:

Series

Returns:

Range for each bar.

Example

>>> rng = candle_range(high, low)
upper_shadow_ratio(open_, high, low, close)[source]

Upper shadow as a fraction of the total candle range.

upper_shadow / (high - low)

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Upper shadow ratio in [0, 1]. Returns 0 when the range is zero.

Example

>>> ratio = upper_shadow_ratio(open_, high, low, close)
Parameters:
Return type:

Series

lower_shadow_ratio(open_, high, low, close)[source]

Lower shadow as a fraction of the total candle range.

lower_shadow / (high - low)

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Lower shadow ratio in [0, 1]. Returns 0 when the range is zero.

Example

>>> ratio = lower_shadow_ratio(open_, high, low, close)
Parameters:
Return type:

Series

body_to_range_ratio(open_, high, low, close)[source]

Body size as a fraction of the total candle range.

abs(close - open) / (high - low)

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Body-to-range ratio in [0, 1]. Returns 0 when the range is zero.

Example

>>> ratio = body_to_range_ratio(open_, high, low, close)
Parameters:
Return type:

Series

candle_direction(open_, close, doji_threshold=0.0)[source]

Candle direction: 1 (bullish), -1 (bearish), 0 (doji).

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • doji_threshold (float, default: 0.0) – Maximum absolute difference between close and open to classify the candle as a doji (default 0.0 — exact equality).

  • open_ (Series)

Return type:

Series

Returns:

Direction for each bar.

Example

>>> direction = candle_direction(open_, close)
Parameters:
Return type:

Series

average_candle_body(open_, close, period=14)[source]

Simple moving average of absolute body sizes.

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – SMA look-back period.

  • open_ (Series)

Return type:

Series

Returns:

Smoothed average body size.

Example

>>> avg_body = average_candle_body(open_, close, period=14)
Parameters:
Return type:

Series

candle_momentum(open_, close, period=5)[source]

Sum of (close - open) over the last period bars.

A positive value indicates net bullish momentum; negative indicates bearish momentum.

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • period (int, default: 5) – Number of bars to sum.

  • open_ (Series)

Return type:

Series

Returns:

Cumulative close-minus-open over the window.

Example

>>> mom = candle_momentum(open_, close, period=5)
Parameters:
Return type:

Series

body_gap(open_, close)[source]

Gap between consecutive candle bodies.

Computed as open[i] - close[i-1], i.e. the distance between the current open and the previous close.

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Body gap for each bar (positive = gap up, negative = gap down).

Example

>>> gap = body_gap(open_, close)
Parameters:
Return type:

Series

inside_bar(high, low)[source]

Detect inside bars.

An inside bar has a high below the previous high and a low above the previous low (the bar is fully contained within the prior bar’s range).

Interpretation:
  • Consolidation / contraction – the market is building energy.

  • Breakout of the inside bar’s range often leads to a significant directional move.

  • Multiple consecutive inside bars = stronger breakout.

Trading rules:
  • Place a buy stop above the inside bar’s high and a sell stop below its low. Trade whichever triggers first.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

Return type:

Series

Returns:

Boolean series (True where an inside bar is detected).

Example

>>> ib = inside_bar(high, low)
outside_bar(high, low)[source]

Detect outside bars (engulfing range).

An outside bar has a high above the previous high and a low below the previous low (the bar’s range completely engulfs the prior bar’s range).

Interpretation:
  • High volatility bar showing a battle between buyers and sellers.

  • The close direction determines who won: close near the high = bullish; close near the low = bearish.

  • Often marks a reversal or a volatility breakout.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

Return type:

Series

Returns:

Boolean series (True where an outside bar is detected).

Example

>>> ob = outside_bar(high, low)
pin_bar(open_, high, low, close, shadow_ratio=2.0)[source]

Detect pin bars.

A pin bar has a long shadow that is at least shadow_ratio times the body size. A bullish pin bar (1) has a long lower shadow; a bearish pin bar (-1) has a long upper shadow.

Interpretation:
  • Bullish pin bar (1): Long lower shadow shows strong rejection of lower prices. Buy signal at support.

  • Bearish pin bar (-1): Long upper shadow shows strong rejection of higher prices. Sell signal at resistance.

  • One of the most widely used price action signals.

  • Most reliable at key support/resistance levels or after a sustained trend.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • shadow_ratio (float, default: 2.0) – Minimum shadow-to-body ratio to qualify (default 2.0).

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish pin bar), -1 (bearish pin bar), or 0.

Example

>>> pb = pin_bar(open_, high, low, close)
Parameters:
Return type:

Series

doji(open_, high, low, close, threshold=0.05)[source]

Doji pattern.

A Doji occurs when the body is very small relative to the total range.

Interpretation:
  • Indecision: Open and close are nearly equal – buyers and sellers are in balance.

  • At resistance: Bearish signal (potential reversal down).

  • At support: Bullish signal (potential reversal up).

  • In a trend: Warning that momentum may be fading.

  • Requires confirmation from the next candle – a doji alone is not a signal.

  • Reliability: Moderate. More significant after a strong trend.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.05) – Maximum body-to-range ratio to qualify as a Doji.

  • open_ (Series)

Returns:

1 where a Doji is detected, 0 otherwise.

Return type:

Series

hammer(open_, high, low, close)[source]

Hammer and Hanging Man pattern.

A hammer has a small body near the top and a long lower shadow (at least 2x the body). Returns 1 for bullish hammer (after a downtrend proxy: prior close < close), -1 for hanging man (after an uptrend proxy: prior close > close), 0 otherwise.

Interpretation:
  • Hammer (1): Bullish reversal after a downtrend. Sellers pushed price down during the session but buyers fought back, closing near the open. The long lower shadow shows rejected selling pressure.

  • Hanging Man (-1): Bearish warning after an uptrend. Same shape, but context differs – suggests sellers are emerging.

  • Confirmation needed: Wait for the next candle to close in the reversal direction.

  • Reliability: High for hammers at major support levels.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 (bullish hammer), -1 (hanging man), or 0.

Return type:

Series

engulfing(open_, high, low, close)[source]

Bullish/Bearish Engulfing pattern.

Interpretation:
  • Bullish engulfing (1): A small bearish candle completely engulfed by a larger bullish candle. Strong reversal signal at the bottom of a downtrend.

  • Bearish engulfing (-1): A small bullish candle completely engulfed by a larger bearish candle. Strong reversal signal at the top of an uptrend.

  • Volume confirmation strengthens the signal.

  • Reliability: High – one of the most reliable reversal patterns, especially at key support/resistance levels.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 (bullish engulfing), -1 (bearish engulfing), or 0.

Return type:

Series

morning_star(open_, high, low, close)[source]

Morning Star (3-candle bullish reversal).

Interpretation:
  • A strong bullish reversal signal at the bottom of a downtrend.

  • Day 1 (large bearish): Bears are in control.

  • Day 2 (small body / doji): Indecision – selling pressure is exhausting.

  • Day 3 (large bullish): Bulls take over, closing above the midpoint of Day 1’s body.

  • Reliability: High – three-candle confirmation reduces false signals. Best at established support levels.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 where a Morning Star is detected, 0 otherwise.

Return type:

Series

evening_star(open_, high, low, close)[source]

Evening Star (3-candle bearish reversal).

Interpretation:
  • The bearish counterpart of the Morning Star.

  • Day 1 (large bullish): Bulls are in control.

  • Day 2 (small body / doji): Indecision at the top.

  • Day 3 (large bearish): Bears take over.

  • Reliability: High – the mirror of Morning Star. Best at established resistance levels.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

-1 where an Evening Star is detected, 0 otherwise.

Return type:

Series

three_white_soldiers(open_, high, low, close)[source]

Three White Soldiers (strong bullish continuation).

Three consecutive bullish candles, each opening within the prior body and closing at a new high.

Interpretation:
  • Strong bullish signal indicating sustained buying pressure.

  • Each candle should have a full body (not spinning tops).

  • Best after a downtrend or consolidation as a reversal signal.

  • Reliability: Very high – three consecutive strong closes show committed buying. Weakened if upper shadows are long (advance block pattern).

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 where the pattern is detected, 0 otherwise.

Return type:

Series

three_black_crows(open_, high, low, close)[source]

Three Black Crows (strong bearish continuation).

Three consecutive bearish candles, each opening within the prior body and closing at a new low.

Interpretation:
  • Strong bearish signal indicating sustained selling pressure.

  • The bearish counterpart of Three White Soldiers.

  • Reliability: Very high – three consecutive strong closes downward show committed selling.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

-1 where the pattern is detected, 0 otherwise.

Return type:

Series

harami(open_, high, low, close)[source]

Harami pattern (bullish and bearish).

The second candle’s body is entirely contained within the first candle’s body.

Interpretation:
  • Bullish harami (1): A large bearish candle followed by a small bullish candle within its body. Suggests selling pressure is weakening. Reversal may follow.

  • Bearish harami (-1): A large bullish candle followed by a small bearish candle within its body. Suggests buying pressure is weakening.

  • Reliability: Moderate – requires confirmation from the following candle. Less reliable than engulfing patterns.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 (bullish harami), -1 (bearish harami), or 0.

Return type:

Series

spinning_top(open_, high, low, close, body_threshold=0.3)[source]

Spinning Top (indecision candle).

A candle with a small body relative to its range and roughly equal upper and lower shadows.

Interpretation:
  • Indecision: Neither buyers nor sellers gained control.

  • In an uptrend: Warns that bulls are losing momentum.

  • In a downtrend: Warns that bears are losing momentum.

  • Not a reversal signal on its own – needs confirmation.

  • Reliability: Low as a standalone signal; moderate when appearing at key levels after a sustained trend.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.3) – Maximum body-to-range ratio.

  • open_ (Series)

Returns:

1 where a Spinning Top is detected, 0 otherwise.

Return type:

Series

marubozu(open_, high, low, close, threshold=0.01)[source]

Marubozu (full-body candle with no/tiny wicks).

Interpretation:
  • Bullish marubozu (1): Opens at the low and closes at the high – buyers dominated the entire session with no pushback. Very strong bullish conviction.

  • Bearish marubozu (-1): Opens at the high and closes at the low – sellers dominated completely.

  • Reliability: High – the absence of shadows shows one side had complete control. Often marks the beginning of a new trend leg.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.01) – Maximum shadow-to-range ratio for each shadow.

  • open_ (Series)

Returns:

1 (bullish marubozu), -1 (bearish marubozu), or 0.

Return type:

Series

piercing_pattern(open_, high, low, close)[source]

Piercing Pattern (bullish reversal).

A two-candle pattern: Day 1 is bearish, Day 2 opens below Day 1’s low and closes above the midpoint of Day 1’s body.

Interpretation:
  • Bullish reversal signal at the bottom of a downtrend.

  • The gap down open followed by a strong close above the midpoint shows buyers stepping in aggressively.

  • Reliability: Moderate-high. Stronger when the close is deeper into Day 1’s body (closer to engulfing).

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 where a Piercing Pattern is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = piercing_pattern(open_, high, low, close)
Parameters:
Return type:

Series

dark_cloud_cover(open_, high, low, close)[source]

Dark Cloud Cover (bearish reversal).

The bearish counterpart of the Piercing Pattern. Day 1 is bullish, Day 2 opens above Day 1’s high and closes below the midpoint of Day 1’s body.

Interpretation:
  • Bearish reversal signal at the top of an uptrend.

  • The gap up open followed by selling down into Day 1’s body shows sellers overpowering buyers.

  • Reliability: Moderate-high. More significant with high volume.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

-1 where a Dark Cloud Cover is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = dark_cloud_cover(open_, high, low, close)
Parameters:
Return type:

Series

hanging_man(open_, high, low, close, trend_period=5)[source]

Hanging Man (bearish reversal at top).

Same hammer shape (small body near top, long lower shadow) but appears after an uptrend, signalling potential reversal.

Interpretation:
  • Bearish warning signal after an uptrend. The long lower shadow shows sellers tested lower prices during the session.

  • Needs confirmation: a bearish close the next day confirms the reversal.

  • Reliability: Moderate – requires confirmation and context.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • trend_period (int, default: 5) – Number of bars to assess prior uptrend.

  • open_ (Series)

Returns:

-1 where a Hanging Man is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = hanging_man(open_, high, low, close)
Parameters:
Return type:

Series

inverted_hammer(open_, high, low, close, trend_period=5)[source]

Inverted Hammer (bullish reversal at bottom).

A candle with a long upper shadow (at least 2x the body) and a small lower shadow, appearing after a downtrend.

Interpretation:
  • Bullish reversal signal at the bottom of a downtrend.

  • The long upper shadow shows buyers tested higher prices but could not hold them yet. If confirmed by next bar, buyers are gaining strength.

  • Reliability: Moderate – requires a bullish confirmation candle the next day.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • trend_period (int, default: 5) – Number of bars to assess prior downtrend.

  • open_ (Series)

Returns:

1 where an Inverted Hammer is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = inverted_hammer(open_, high, low, close)
Parameters:
Return type:

Series

shooting_star(open_, high, low, close, trend_period=5)[source]

Shooting Star (bearish reversal at top).

Same shape as inverted hammer (long upper shadow, small lower shadow) but appears after an uptrend.

Interpretation:
  • Bearish reversal signal at the top of an uptrend. Buyers pushed price higher but sellers overwhelmed them, closing near the open.

  • The long upper shadow represents rejected higher prices.

  • Reliability: Moderate-high – stronger when it appears at resistance with high volume.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • trend_period (int, default: 5) – Number of bars to assess prior uptrend.

  • open_ (Series)

Returns:

-1 where a Shooting Star is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = shooting_star(open_, high, low, close)
Parameters:
Return type:

Series

tweezer_top(open_, high, low, close, tolerance=0.001)[source]

Tweezer Top (bearish reversal).

Two consecutive candles with nearly the same highs. The first candle is bullish and the second is bearish.

Interpretation:
  • Bearish reversal at a resistance level. Both candles tested the same high and were rejected, showing strong resistance.

  • Reliability: Moderate – stronger at established resistance.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.001) – Maximum relative difference between highs to be considered equal.

  • open_ (Series)

Returns:

-1 where a Tweezer Top is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = tweezer_top(open_, high, low, close)
Parameters:
Return type:

Series

tweezer_bottom(open_, high, low, close, tolerance=0.001)[source]

Tweezer Bottom (bullish reversal).

Two consecutive candles with nearly the same lows. The first candle is bearish and the second is bullish.

Interpretation:
  • Bullish reversal at a support level. Both candles tested the same low and were rejected, showing strong support.

  • Reliability: Moderate – stronger at established support.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.001) – Maximum relative difference between lows to be considered equal.

  • open_ (Series)

Returns:

1 where a Tweezer Bottom is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = tweezer_bottom(open_, high, low, close)
Parameters:
Return type:

Series

three_inside_up(open_, high, low, close)[source]

Three Inside Up (bullish reversal).

A three-candle pattern: bullish harami (Days 1-2) confirmed by a third bullish candle closing above Day 1’s open.

Interpretation:
  • A confirmed bullish harami. The third candle provides the confirmation that a simple harami lacks.

  • Reliability: High – three-candle confirmation is stronger than the two-candle harami alone.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 where the pattern is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = three_inside_up(open_, high, low, close)
Parameters:
Return type:

Series

three_inside_down(open_, high, low, close)[source]

Three Inside Down (bearish reversal).

A three-candle pattern: bearish harami (Days 1-2) confirmed by a third bearish candle closing below Day 1’s open.

Interpretation:
  • A confirmed bearish harami. The bearish counterpart of Three Inside Up.

  • Reliability: High – three-candle confirmation pattern.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

-1 where the pattern is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = three_inside_down(open_, high, low, close)
Parameters:
Return type:

Series

abandoned_baby(open_, high, low, close)[source]

Abandoned Baby (reversal pattern).

A rare three-candle pattern with gaps. A Doji star gaps away from the first candle and the third candle gaps in the opposite direction.

Interpretation:
  • Bullish abandoned baby (1): Bearish candle, gap-down doji, gap-up bullish candle. Very strong reversal signal.

  • Bearish abandoned baby (-1): Bullish candle, gap-up doji, gap-down bearish candle. Very strong reversal signal.

  • Reliability: Very high – but extremely rare. The gap isolation of the doji shows a dramatic sentiment shift.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 (bullish abandoned baby), -1 (bearish abandoned baby), or 0.

Return type:

Series

Example

>>> signal = abandoned_baby(open_, high, low, close)
Parameters:
Return type:

Series

kicking(open_, high, low, close, threshold=0.01)[source]

Kicking pattern.

Two consecutive marubozu candles in opposite directions with a gap between them. One of the strongest reversal signals.

Interpretation:
  • Bullish kicking (1): Bearish marubozu followed by a gap-up bullish marubozu. Extremely strong reversal.

  • Bearish kicking (-1): Bullish marubozu followed by a gap-down bearish marubozu.

  • Reliability: Very high – one of the most powerful candlestick patterns. The opposing full-body candles with a gap show a complete and sudden sentiment reversal.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.01) – Maximum shadow-to-range ratio for marubozu qualification.

  • open_ (Series)

Returns:

1 (bullish kicking), -1 (bearish kicking), or 0.

Return type:

Series

Example

>>> signal = kicking(open_, high, low, close)
Parameters:
Return type:

Series

belt_hold(open_, high, low, close, threshold=0.01)[source]

Belt Hold pattern.

A long marubozu candle that opens with a gap in the direction of the prior trend. A bullish belt hold gaps down and opens at the low; a bearish belt hold gaps up and opens at the high.

Interpretation:
  • Bullish belt hold (1): Gaps down then rallies all day closing near the high – strong rejection of lower prices.

  • Bearish belt hold (-1): Gaps up then sells off all day.

  • Reliability: Moderate – the gap adds significance.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.01) – Maximum shadow-to-range ratio for the relevant shadow.

  • open_ (Series)

Returns:

1 (bullish belt hold), -1 (bearish belt hold), or 0.

Return type:

Series

Example

>>> signal = belt_hold(open_, high, low, close)
Parameters:
Return type:

Series

rising_three_methods(open_, high, low, close)[source]

Rising Three Methods (bullish continuation).

A five-candle pattern: a long bullish candle, followed by three small bearish candles that stay within the first candle’s range, then a final long bullish candle that closes above the first candle’s close.

Interpretation:
  • Bullish continuation pattern – the three small bearish candles are a rest/consolidation within the uptrend.

  • The final bullish candle confirms the trend resumes.

  • Reliability: High – five-candle confirmation shows clear trend continuation with a healthy pullback.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 where the pattern is detected, 0 otherwise.

Example

>>> signal = rising_three_methods(open_, high, low, close)
Parameters:
Return type:

Series

falling_three_methods(open_, high, low, close)[source]

Falling Three Methods (bearish continuation).

The bearish counterpart of Rising Three Methods. A long bearish candle, three small bullish candles inside its range, then a final long bearish candle that closes below the first candle’s close.

Interpretation:
  • Bearish continuation pattern – the small bullish candles are a brief consolidation within the downtrend.

  • Reliability: High – mirror of Rising Three Methods.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

-1 where the pattern is detected, 0 otherwise.

Example

>>> signal = falling_three_methods(open_, high, low, close)
Parameters:
Return type:

Series

tasuki_gap(open_, high, low, close)[source]

Upside/Downside Tasuki Gap.

Upside (1): two bullish candles with a gap up, followed by a bearish candle that opens within the second body and closes within the gap but does not fill it.

Downside (-1): two bearish candles with a gap down, followed by a bullish candle that opens within the second body and closes within the gap but does not fill it.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 (upside Tasuki gap), -1 (downside Tasuki gap), or 0.

Example

>>> signal = tasuki_gap(open_, high, low, close)
Parameters:
Return type:

Series

on_neck(open_, high, low, close, tolerance=0.001)[source]

On Neck pattern (bearish continuation).

A bearish candle followed by a small bullish candle that opens below the previous low and closes at or near the previous low.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.001) – Maximum relative difference between close and previous low.

  • open_ (Series)

Return type:

Series

Returns:

-1 where the pattern is detected, 0 otherwise.

Example

>>> signal = on_neck(open_, high, low, close)
Parameters:
Return type:

Series

in_neck(open_, high, low, close, tolerance=0.003)[source]

In Neck pattern (slight bullish variant of On Neck).

A bearish candle followed by a small bullish candle that opens below the previous low and closes slightly above (but near) the previous close.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.003) – Maximum relative distance above the previous close.

  • open_ (Series)

Return type:

Series

Returns:

-1 where the pattern is detected, 0 otherwise.

Example

>>> signal = in_neck(open_, high, low, close)
Parameters:
Return type:

Series

thrusting(open_, high, low, close)[source]

Thrusting pattern (moderate bearish continuation).

A bearish candle followed by a bullish candle that opens below the previous low and closes above the previous close but below the midpoint of the previous body.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

-1 where the pattern is detected, 0 otherwise.

Example

>>> signal = thrusting(open_, high, low, close)
Parameters:
Return type:

Series

separating_lines(open_, high, low, close, tolerance=0.001)[source]

Bullish/Bearish Separating Lines.

Bullish (1): a bearish candle followed by a bullish candle that opens at the same level as the previous open.

Bearish (-1): a bullish candle followed by a bearish candle that opens at the same level as the previous open.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.001) – Maximum relative difference between opens.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish), -1 (bearish), or 0.

Example

>>> signal = separating_lines(open_, high, low, close)
Parameters:
Return type:

Series

closing_marubozu(open_, high, low, close, threshold=0.01)[source]

Closing Marubozu — no shadow on the closing side only.

A bullish closing marubozu (1) has no upper shadow (close == high) but may have a lower shadow. A bearish closing marubozu (-1) has no lower shadow (close == low) but may have an upper shadow.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.01) – Maximum shadow-to-range ratio for the closing side.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish), -1 (bearish), or 0.

Example

>>> signal = closing_marubozu(open_, high, low, close)
Parameters:
Return type:

Series

rickshaw_man(open_, high, low, close, body_threshold=0.05, shadow_threshold=0.3)[source]

Rickshaw Man – a Doji with very long shadows and tiny body near center.

Interpretation:
  • Extreme indecision: price moved significantly in both directions but closed near the open at the midpoint.

  • Suggests the market is at a critical juncture.

  • Reliability: Moderate – needs context and confirmation.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.05) – Maximum body-to-range ratio to qualify.

  • shadow_threshold (float, default: 0.3) – Minimum shadow-to-range ratio for each shadow.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = rickshaw_man(open_, high, low, close)
Parameters:
Return type:

Series

long_legged_doji(open_, high, low, close, body_threshold=0.05, shadow_threshold=0.3)[source]

Long Legged Doji – Doji with unusually long upper and lower shadows.

Interpretation:
  • Strong indecision with high volatility. Both buyers and sellers were active but neither won.

  • More significant than a standard doji due to the wide range.

  • Reliability: Moderate – similar to Rickshaw Man.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.05) – Maximum body-to-range ratio.

  • shadow_threshold (float, default: 0.3) – Minimum shadow-to-range ratio for each shadow.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = long_legged_doji(open_, high, low, close)
Parameters:
Return type:

Series

dragonfly_doji(open_, high, low, close, body_threshold=0.05, upper_threshold=0.05, lower_min=0.3)[source]

Dragonfly Doji – Doji with a long lower shadow and no upper shadow.

Interpretation:
  • Bullish signal, especially after a downtrend. Sellers pushed price down but buyers brought it all the way back to the open.

  • The long lower shadow shows strong rejection of lower prices.

  • Reliability: Moderate-high at support levels.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.05) – Maximum body-to-range ratio.

  • upper_threshold (float, default: 0.05) – Maximum upper-shadow-to-range ratio.

  • lower_min (float, default: 0.3) – Minimum lower-shadow-to-range ratio.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = dragonfly_doji(open_, high, low, close)
Parameters:
Return type:

Series

gravestone_doji(open_, high, low, close, body_threshold=0.05, lower_threshold=0.05, upper_min=0.3)[source]

Gravestone Doji – Doji with a long upper shadow and no lower shadow.

Interpretation:
  • Bearish signal, especially after an uptrend. Buyers pushed price up but sellers brought it all the way back to the open.

  • The long upper shadow shows strong rejection of higher prices.

  • Reliability: Moderate-high at resistance levels.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.05) – Maximum body-to-range ratio.

  • lower_threshold (float, default: 0.05) – Maximum lower-shadow-to-range ratio.

  • upper_min (float, default: 0.3) – Minimum upper-shadow-to-range ratio.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = gravestone_doji(open_, high, low, close)
Parameters:
Return type:

Series

tri_star(open_, high, low, close, doji_threshold=0.05)[source]

Tri-Star pattern – three consecutive dojis with gaps.

Interpretation:
  • Bullish tri-star (1): Three dojis where the middle gaps below. Very rare, strong reversal at bottoms.

  • Bearish tri-star (-1): Three dojis where the middle gaps above. Very rare, strong reversal at tops.

  • Reliability: Very high when it occurs, but extremely rare.

Bullish (1): three dojis where the middle gaps below the other two. Bearish (-1): three dojis where the middle gaps above the other two.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • doji_threshold (float, default: 0.05) – Maximum body-to-range ratio for doji qualification.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish tri-star), -1 (bearish tri-star), or 0.

Example

>>> signal = tri_star(open_, high, low, close)
Parameters:
Return type:

Series

unique_three_river(open_, high, low, close)[source]

Unique Three River Bottom (rare bullish reversal).

Day 1: long bearish candle. Day 2: harami-like bearish candle with a lower low. Day 3: small bullish candle that closes below Day 2’s close.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = unique_three_river(open_, high, low, close)
Parameters:
Return type:

Series

concealing_baby_swallow(open_, high, low, close, marubozu_threshold=0.02)[source]

Concealing Baby Swallow (four-candle bearish pattern).

Four bearish candles: Days 1-2 are bearish marubozus. Day 3 gaps down, has a long upper shadow into Day 2’s body. Day 4 engulfs Day 3 including the shadow.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • marubozu_threshold (float, default: 0.02) – Maximum shadow-to-range ratio for marubozu.

  • open_ (Series)

Return type:

Series

Returns:

-1 where detected, 0 otherwise.

Example

>>> signal = concealing_baby_swallow(open_, high, low, close)
Parameters:
Return type:

Series

higher_highs_lows(high, low, period=5)[source]

Detect sequences of HH/HL (uptrend) or LH/LL (downtrend).

Compares rolling highest-high and lowest-low over period bars to determine whether the market is making higher highs & higher lows (uptrend = 1), lower highs & lower lows (downtrend = -1), or neither (0).

Interpretation:
  • 1 (HH+HL): Classic uptrend structure. Price is making higher highs and higher lows – the textbook definition of an uptrend.

  • -1 (LH+LL): Classic downtrend structure.

  • 0: No clear trend – consolidation, range, or transition.

  • When the sequence breaks (e.g. first lower low in an uptrend), it is an early warning of potential trend reversal.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 5) – Look-back window for swing comparison.

Return type:

Series

Returns:

1 (uptrend / HH+HL), -1 (downtrend / LH+LL), or 0.

Example

>>> trend = higher_highs_lows(high, low, period=5)
swing_high(high, lookback=2, lookahead=2)[source]

Detect swing highs.

A swing high is a bar whose high is greater than the highs of the lookback bars before it and the lookahead bars after it.

Parameters:
  • high (Series) – High prices.

  • lookback (int, default: 2) – Number of bars to look back.

  • lookahead (int, default: 2) – Number of bars to look ahead.

Return type:

Series

Returns:

Boolean series (True at swing highs).

Example

>>> sh = swing_high(high, lookback=2, lookahead=2)
swing_low(low, lookback=2, lookahead=2)[source]

Detect swing lows.

A swing low is a bar whose low is less than the lows of the lookback bars before it and the lookahead bars after it.

Parameters:
  • low (Series) – Low prices.

  • lookback (int, default: 2) – Number of bars to look back.

  • lookahead (int, default: 2) – Number of bars to look ahead.

Return type:

Series

Returns:

Boolean series (True at swing lows).

Example

>>> sl = swing_low(low, lookback=2, lookahead=2)
trend_bars(close)[source]

Count consecutive up/down bars.

Returns a running count: positive values for consecutive up bars (close > previous close), negative values for consecutive down bars (close < previous close). The count resets to 0 on a flat bar.

Parameters:

close (Series) – Close prices.

Return type:

Series

Returns:

Consecutive bar count (positive = up streak, negative = down streak).

Example

>>> streaks = trend_bars(close)
gap_analysis(open_, high, low, close, avg_range_period=20, breakaway_threshold=1.5)[source]

Detect and classify gaps.

Gaps are classified as:

  • common — gap size is below the average range

  • breakaway — gap size exceeds breakaway_threshold times the average range

  • exhaustion — gap that occurs after a sustained move (approximated by comparing the current close to a look-back SMA)

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • avg_range_period (int, default: 20) – Period for computing the average range.

  • breakaway_threshold (float, default: 1.5) – Multiplier of average range for breakaway classification.

  • open_ (Series)

Return type:

dict[str, Series]

Returns:

Dictionary with keys gap_size, gap_direction, and gap_type.

  • gap_size — absolute gap size

  • gap_direction — 1 (gap up), -1 (gap down), 0 (no gap)

  • gap_type — categorical string ("common", "breakaway", "exhaustion", or "" for no gap)

Example

>>> result = gap_analysis(open_, high, low, close)
>>> result["gap_type"]
Parameters:
Return type:

dict[str, Series]

range_expansion(high, low, period=14, threshold=1.5)[source]

Detect range expansion (current range significantly above average).

Returns True when (high - low) > threshold * avg_range.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 14) – Look-back for average range.

  • threshold (float, default: 1.5) – Multiplier of average range to trigger expansion.

Return type:

Series

Returns:

Boolean series (True where range is expanded).

Example

>>> expanded = range_expansion(high, low)
narrow_range(high, low, period=4)[source]

NR4/NR7 detection — narrowest range in period bars.

Returns True when the current bar’s range is the smallest in the last period bars (including itself). period=4 gives NR4; period=7 gives NR7.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 4) – Look-back window (default 4 for NR4).

Return type:

Series

Returns:

Boolean series (True at narrow-range bars).

Example

>>> nr4 = narrow_range(high, low, period=4)
>>> nr7 = narrow_range(high, low, period=7)
wide_range_bar(high, low, period=14, threshold=1.5)[source]

Wide Range Bar (WRB): range > threshold * average range.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 14) – Look-back for average range.

  • threshold (float, default: 1.5) – Multiplier (default 1.5).

Return type:

Series

Returns:

Boolean series (True at wide-range bars).

Example

>>> wrb = wide_range_bar(high, low)
key_reversal(open_, high, low, close)[source]

Detect key reversal bars.

A bullish key reversal (1) makes a new low (below the previous low) but closes above the previous close.

A bearish key reversal (-1) makes a new high (above the previous high) but closes below the previous close.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish key reversal), -1 (bearish key reversal), or 0.

Example

>>> kr = key_reversal(open_, high, low, close)
Parameters:
Return type:

Series

pivot_reversal(open_, high, low, close)[source]

Detect two-bar pivot reversal patterns at swing points.

A bullish pivot reversal (1): the previous bar makes a lower low than its predecessor, and the current bar closes above the previous bar’s high.

A bearish pivot reversal (-1): the previous bar makes a higher high than its predecessor, and the current bar closes below the previous bar’s low.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish pivot reversal), -1 (bearish pivot reversal), or 0.

Example

>>> pr = pivot_reversal(open_, high, low, close)
Parameters:
Return type:

Series

crossover(series1, series2)[source]

Detect when series1 crosses above series2.

Interpretation:
  • Returns True on the exact bar where series1 moves from below-or-equal to above series2.

  • Common uses: MA crossovers, RSI crossing above 30, MACD crossing above signal line.

  • Only fires on the transition bar, not on subsequent bars where series1 remains above series2.

Parameters:
  • series1 (Series) – First data series.

  • series2 (Series | float | int) – Second data series or constant level.

Returns:

Boolean series — True on bars where series1 crosses above series2.

Return type:

Series

crossunder(series1, series2)[source]

Detect when series1 crosses below series2.

Interpretation:
  • Returns True on the exact bar where series1 moves from above-or-equal to below series2.

  • Common uses: MA death crosses, RSI crossing below 70, MACD crossing below signal line.

Parameters:
  • series1 (Series) – First data series.

  • series2 (Series | float | int) – Second data series or constant level.

Returns:

Boolean series — True on bars where series1 crosses below series2.

Return type:

Series

above(series1, series2)[source]

Element-wise series1 > series2.

Parameters:
  • series1 (Series) – First data series.

  • series2 (Series | float | int) – Second data series or constant level.

Returns:

Boolean series.

Return type:

Series

below(series1, series2)[source]

Element-wise series1 < series2.

Parameters:
  • series1 (Series) – First data series.

  • series2 (Series | float | int) – Second data series or constant level.

Returns:

Boolean series.

Return type:

Series

rising(data, period=1)[source]

Detect whether data is rising (each bar higher than period bars ago).

Parameters:
  • data (Series) – Data series.

  • period (int, default: 1) – Number of bars to look back.

Returns:

Boolean series.

Return type:

Series

falling(data, period=1)[source]

Detect whether data is falling (each bar lower than period bars ago).

Parameters:
  • data (Series) – Data series.

  • period (int, default: 1) – Number of bars to look back.

Returns:

Boolean series.

Return type:

Series

highest(data, period=14)[source]

Rolling highest value over period bars.

Parameters:
  • data (Series) – Data series.

  • period (int, default: 14) – Rolling window size.

Returns:

Rolling maximum.

Return type:

Series

lowest(data, period=14)[source]

Rolling lowest value over period bars.

Parameters:
  • data (Series) – Data series.

  • period (int, default: 14) – Rolling window size.

Returns:

Rolling minimum.

Return type:

Series

normalize(data, period=None)[source]

Z-score normalization.

When period is None, the full-series mean and standard deviation are used. When period is given, a rolling z-score is computed.

Parameters:
  • data (Series) – Data series.

  • period (int | None, default: None) – Rolling window for mean/std. None uses the entire series.

Returns:

Z-score normalized values.

Return type:

Series

zscore(data, period=20)[source]

Rolling z-score of price.

Measures how many standard deviations the current value is from the rolling mean.

Interpretation:
  • > +2: Price is 2+ standard deviations above mean – statistically unusual (overbought).

  • < -2: Price is 2+ standard deviations below mean – statistically unusual (oversold).

  • Near 0: Price is near its rolling average (fair value).

  • Mean-reversion traders buy at z < -2 and sell at z > +2.

  • In trending markets, z-score can stay extreme for extended periods – use with a trend filter.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Z-score values (unbounded).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13])
>>> zscore(close, period=5)
percentile_rank(data, period=20)[source]

Rolling percentile rank.

Computes the percentage of values within the rolling window that are less than or equal to the current value.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Percentile rank in [0, 100].

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13])
>>> percentile_rank(close, period=5)
mean_deviation(data, period=20)[source]

Rolling mean absolute deviation.

Computes the average of absolute deviations from the rolling mean.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Mean absolute deviation values (>= 0).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13])
>>> mean_deviation(close, period=5)
median(data, period=20)[source]

Rolling median.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Rolling median values.

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13])
>>> median(close, period=5)
skewness(data, period=20)[source]

Rolling skewness.

Measures the asymmetry of the distribution of values within the rolling window. Uses Fisher’s definition (bias-corrected).

Interpretation:
  • Positive skew: Distribution has a long right tail – occasional large positive moves (typical of call option payoffs).

  • Negative skew: Distribution has a long left tail – occasional large negative moves (crash risk).

  • Near 0: Symmetric distribution (normal-like).

  • Negative skew in returns is common for equities – tail risk is to the downside.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length (must be >= 3).

Returns:

Skewness values (unbounded).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series(range(30), dtype=float)
>>> skewness(close, period=20)
kurtosis(data, period=20)[source]

Rolling kurtosis (excess kurtosis, Fisher’s definition).

Measures the tailedness of the distribution of values within the rolling window. Normal distribution has excess kurtosis of 0.

Interpretation:
  • > 0 (leptokurtic): Fatter tails than normal – more extreme moves than a Gaussian would predict. Common in financial returns.

  • < 0 (platykurtic): Thinner tails than normal – fewer extreme moves.

  • Near 0 (mesokurtic): Normal-like tail behavior.

  • High kurtosis warns of tail risk – standard VaR and Gaussian-based risk models will underestimate risk.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length (must be >= 4).

Returns:

Excess kurtosis values (unbounded).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series(range(30), dtype=float)
>>> kurtosis(close, period=20)
entropy(data, period=20, bins=10)[source]

Rolling Shannon entropy of binned price changes.

Discretises the price changes within the rolling window into bins equal-width bins and computes Shannon entropy in nats (natural log).

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

  • bins (int, default: 10) – Number of histogram bins for discretisation.

Returns:

Shannon entropy values (>= 0).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series(range(30), dtype=float)
>>> entropy(close, period=20, bins=5)
hurst_exponent(data, period=100)[source]

Rolling Hurst exponent via the rescaled range (R/S) method.

  • H < 0.5: mean-reverting

  • H = 0.5: random walk

  • H > 0.5: trending

Parameters:
  • data (Series) – Price series.

  • period (int, default: 100) – Rolling window length (should be >= 20 for reliable estimates).

Returns:

Hurst exponent estimates in roughly [0, 1].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> close = pd.Series(100 + np.cumsum(np.random.randn(200)))
>>> hurst_exponent(close, period=100)
correlation(data, other, period=20)[source]

Rolling Pearson correlation between two series.

Parameters:
  • data (Series) – First price series.

  • other (Series) – Second price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Correlation values in [-1, 1].

Return type:

Series

Example

>>> import pandas as pd
>>> x = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=float)
>>> y = pd.Series([2, 4, 6, 8, 10, 12, 14, 16, 18, 20], dtype=float)
>>> correlation(x, y, period=5)
beta(data, benchmark, period=60)[source]

Rolling beta (OLS slope of data returns vs benchmark returns).

Interpretation:
  • Beta = 1: Asset moves in line with the benchmark.

  • Beta > 1: Asset is more volatile than the benchmark (amplifies market moves). E.g. beta = 1.5 means the stock moves 1.5% for every 1% benchmark move.

  • Beta < 1: Asset is less volatile than the benchmark.

  • Beta < 0: Asset moves inversely to the benchmark (rare).

  • Rising beta: Asset becoming more correlated/volatile relative to benchmark.

  • Beta is the cornerstone of CAPM and factor models.

Parameters:
  • data (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • period (int, default: 60) – Rolling window length.

Returns:

Beta values (unbounded).

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> stock = pd.Series(100 + np.cumsum(np.random.randn(100)))
>>> market = pd.Series(100 + np.cumsum(np.random.randn(100)))
>>> beta(stock, market, period=30)
r_squared(data, benchmark, period=60)[source]

Rolling R-squared (coefficient of determination).

Computed as the square of the rolling Pearson correlation of returns.

Parameters:
  • data (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • period (int, default: 60) – Rolling window length.

Returns:

R-squared values in [0, 1].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> stock = pd.Series(100 + np.cumsum(np.random.randn(100)))
>>> market = pd.Series(100 + np.cumsum(np.random.randn(100)))
>>> r_squared(stock, market, period=30)
information_coefficient(data, other, period=20)[source]

Rolling information coefficient (Spearman rank correlation).

Measures the rolling rank correlation between two series, commonly used to evaluate forecast skill.

Parameters:
  • data (Series) – Forecast or signal series.

  • other (Series) – Realised outcome series.

  • period (int, default: 20) – Rolling window length.

Returns:

IC values in [-1, 1].

Return type:

Series

Example

>>> import pandas as pd
>>> forecast = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=float)
>>> actual = pd.Series([2, 1, 4, 3, 6, 5, 8, 7, 10, 9], dtype=float)
>>> information_coefficient(forecast, actual, period=5)
hilbert_transform_dominant_period(data, min_period=6, max_period=50)[source]

Dominant cycle period via Hilbert Transform.

Uses Ehlers’ Hilbert Transform Discriminator to estimate the dominant cycle period of the price series.

Interpretation:
  • Output is the estimated cycle length in bars (e.g. 20 means the dominant cycle repeats every 20 bars).

  • Use this to adaptively set indicator periods: instead of a fixed 14-period RSI, use the dominant period.

  • Short period (< 10): Fast cycling market.

  • Long period (> 30): Slow cycling or trending market.

  • Stable readings = well-defined cycle. Erratic readings = no clear cycle (trending or random).

Parameters:
  • data (Series) – Price series (typically close).

  • min_period (int, default: 6) – Minimum allowed cycle period.

  • max_period (int, default: 50) – Maximum allowed cycle period.

Returns:

Estimated dominant cycle period in bars.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> hilbert_transform_dominant_period(close)
hilbert_transform_trend_mode(data)[source]

Trend vs cycle mode indicator via Hilbert Transform.

Returns +1 when the market is in trend mode and 0 when in cycle mode, based on the relationship between the dominant cycle period and a simple moving average smoothing window.

Parameters:

data (Series) – Price series.

Returns:

Binary series: 1 = trending, 0 = cycling.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> hilbert_transform_trend_mode(close)
hilbert_instantaneous_phase(data)[source]

Instantaneous trendline via Hilbert Transform.

Computes a smooth trendline by applying the dominant cycle period as an adaptive moving average length.

Parameters:

data (Series) – Price series.

Returns:

Instantaneous trendline values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> hilbert_instantaneous_phase(close)
sine_wave(data)[source]

Ehlers Sine Wave indicator.

Uses the dominant cycle period to compute the sine and lead-sine values, generating buy/sell signals on crossovers.

Interpretation:
  • Sine crosses above lead_sine: Buy signal (cycle turning up).

  • Sine crosses below lead_sine: Sell signal (cycle turning down).

  • When both values are near +/-1, the market is in cycle mode.

  • When values are erratic or near zero, the market may be trending rather than cycling.

Parameters:

data (Series) – Price series.

Returns:

sine and lead_sine series.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> result = sine_wave(close)
even_better_sinewave(data, hp_period=40, ss_period=10)[source]

Ehlers Even Better Sinewave (EBSW).

Combines a high-pass filter, super-smoother, and autocorrelation to produce an oscillator that identifies the dominant cycle.

Interpretation:
  • Near +1: Cycle is at or near a peak.

  • Near -1: Cycle is at or near a trough.

  • Zero crossover up: Cycle turning bullish.

  • Zero crossover down: Cycle turning bearish.

  • More reliable than the original Sine Wave indicator because it better separates cycle from trend components.

Parameters:
  • data (Series) – Price series.

  • hp_period (int, default: 40) – High-pass filter period.

  • ss_period (int, default: 10) – Super-smoother period.

Returns:

EBSW oscillator values in approximately [-1, 1].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> even_better_sinewave(close)
roofing_filter(data, hp_period=48, lp_period=10)[source]

Ehlers Roofing Filter.

Applies a high-pass filter followed by a super-smoother low-pass filter to isolate the dominant cycle from both trend and noise.

Interpretation:
  • Output oscillates around zero, showing the pure cycle component of price.

  • Positive: Cycle is in the up phase.

  • Negative: Cycle is in the down phase.

  • Use to identify cycle turning points without trend or noise contamination.

Parameters:
  • data (Series) – Price series.

  • hp_period (int, default: 48) – High-pass filter cutoff period.

  • lp_period (int, default: 10) – Low-pass (super-smoother) cutoff period.

Returns:

Filtered cycle component.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> roofing_filter(close)
decycler(data, hp_period=125)[source]

Ehlers Decycler.

Removes the cycle component from the price series, keeping only the trend. Computed as price - highpass(price).

Interpretation:
  • Shows the pure trend component of price with cycles removed.

  • Price above decycler: Bullish trend.

  • Price below decycler: Bearish trend.

  • Extremely smooth with virtually no lag – one of the best trend-following overlays available.

Parameters:
  • data (Series) – Price series.

  • hp_period (int, default: 125) – High-pass filter cutoff period. Components with period shorter than this are removed (cycles).

Returns:

Trend-only (decycled) series.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> decycler(close)
bandpass_filter(data, period=20, bandwidth=0.3)[source]

Ehlers Bandpass Filter.

Isolates the cycle component at the specified period. Returns both the bandpass filter output and a trigger signal (one-bar lag).

Interpretation:
  • BP crosses above trigger: Buy signal (cycle turning up).

  • BP crosses below trigger: Sell signal (cycle turning down).

  • BP at peak: Cycle high – potential sell zone.

  • BP at trough: Cycle low – potential buy zone.

  • Only isolates the cycle at the specified period; other frequencies are filtered out.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Centre period of the bandpass.

  • bandwidth (float, default: 0.3) – Bandwidth as a fraction of the centre frequency.

Returns:

bp (bandpass) and trigger (one-bar lag of bp).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> result = bandpass_filter(close, period=20)
squeeze_momentum(high, low, close, bb_period=20, bb_std=2.0, kc_period=20, kc_mult=1.5, mom_period=12)[source]

TTM Squeeze Momentum indicator.

Detects when Bollinger Bands are inside Keltner Channels (the “squeeze”) and measures momentum via a linear regression of price.

Interpretation:
  • squeeze_on = 1: Bollinger Bands are inside Keltner Channels. Volatility is compressed. A breakout is imminent.

  • squeeze_on = 0: No squeeze. Normal volatility.

  • Momentum positive: Bullish momentum – breakout likely up.

  • Momentum negative: Bearish momentum – breakout likely down.

  • Momentum growing: Accelerating.

  • Momentum shrinking: Decelerating.

Trading rules:
  • When squeeze fires (transitions from on to off), enter in the direction of momentum.

  • Exit when momentum starts to decelerate (histogram shrinks).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • bb_period (int, default: 20) – Bollinger Bands SMA period.

  • bb_std (float, default: 2.0) – Bollinger Bands standard deviation multiplier.

  • kc_period (int, default: 20) – Keltner Channel EMA period.

  • kc_mult (float, default: 1.5) – Keltner Channel ATR multiplier.

  • mom_period (int, default: 12) – Momentum linear regression period.

Returns:

squeeze_on (bool: 1 = squeeze active), momentum (momentum histogram values).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> n = 100
>>> c = pd.Series(100 + np.cumsum(np.random.randn(n) * 0.5))
>>> h = c + abs(np.random.randn(n) * 0.3)
>>> lo = c - abs(np.random.randn(n) * 0.3)
>>> result = squeeze_momentum(h, lo, c)
anchored_vwap(close, volume, anchor_index=0)[source]

VWAP anchored from a specific bar index.

Computes the Volume Weighted Average Price starting from anchor_index onwards. Values before the anchor are NaN.

Parameters:
  • close (Series) – Close (or typical) prices.

  • volume (Series) – Volume series.

  • anchor_index (int, default: 0) – The integer position index to begin the VWAP calculation from.

Returns:

Anchored VWAP values.

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13], dtype=float)
>>> volume = pd.Series([100, 200, 150, 300, 250, 100, 200, 150, 300, 250], dtype=float)
>>> anchored_vwap(close, volume, anchor_index=3)
linear_regression_channel(data, period=100, std_dev=2.0)[source]

Linear regression channel with standard deviation bands.

Fits a rolling linear regression and constructs upper/lower channel lines based on the standard error.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 100) – Rolling window length for the regression.

  • std_dev (float, default: 2.0) – Number of standard deviations for the channel width.

Returns:

middle (regression value), upper, lower.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(120, dtype=float) * 0.5)
>>> result = linear_regression_channel(close, period=50)
pivot_points(high, low, close, method='standard')[source]

Pivot points with support and resistance levels.

Computes pivot point and two levels of support/resistance using the prior bar’s high, low, and close.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • method (str, default: 'standard') – Calculation method: "standard", "fibonacci", or "woodie".

Returns:

pivot, s1, s2, r1, r2.

Return type:

dict[str, Series]

Example

>>> import pandas as pd
>>> h = pd.Series([12, 13, 14, 13, 12], dtype=float)
>>> lo = pd.Series([10, 11, 12, 11, 10], dtype=float)
>>> c = pd.Series([11, 12, 13, 12, 11], dtype=float)
>>> result = pivot_points(h, lo, c)
market_structure(high, low, lookback=5)[source]

Higher highs / lower lows market structure detection.

Identifies swing highs and lows using a lookback window, then labels each swing as higher-high (HH), lower-high (LH), higher-low (HL), or lower-low (LL).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • lookback (int, default: 5) – Number of bars on each side to confirm a swing point.

Returns:

swing_high (high values at swing highs, else NaN), swing_low (low values at swing lows, else NaN), structure (1 = bullish / HH+HL, -1 = bearish / LH+LL, 0 = neutral).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(50) * 0.5) + 1)
>>> lo = h - 2
>>> result = market_structure(h, lo, lookback=3)
swing_points(high, low, lookback=5)[source]

Swing high and low detection.

A swing high occurs when the high is the maximum of 2 * lookback + 1 bars centred on the pivot bar. Symmetrically for swing lows.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • lookback (int, default: 5) – Number of bars on each side of the pivot.

Returns:

swing_high (high values at swing highs, else NaN), swing_low (low values at swing lows, else NaN).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(50) * 0.5) + 1)
>>> lo = h - 2
>>> result = swing_points(h, lo, lookback=3)
volume_weighted_macd(close, volume, fast=12, slow=26, signal=9)[source]

MACD weighted by volume.

Uses volume-weighted moving averages instead of standard EMAs for the fast and slow lines.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume series.

  • fast (int, default: 12) – Fast VWMA period.

  • slow (int, default: 26) – Slow VWMA period.

  • signal (int, default: 9) – Signal EMA period.

Returns:

macd, signal, histogram.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> c = pd.Series(100 + np.cumsum(np.random.randn(100) * 0.5))
>>> v = pd.Series(np.random.randint(1000, 10000, 100), dtype=float)
>>> result = volume_weighted_macd(c, v)
ehlers_fisher(high, low, period=10)[source]

Ehlers Fisher Transform.

Converts prices into a Gaussian normal distribution to create sharp turning points, making it easier to identify reversals.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 10) – Look-back period for the normalisation.

Returns:

fisher and trigger (one-bar lag of fisher).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(100) * 0.5) + 1)
>>> lo = h - 2
>>> result = ehlers_fisher(h, lo)
adaptive_rsi(data, base_period=14, vol_period=10, min_period=5, max_period=50)[source]

RSI with an adaptive period based on volatility.

The look-back period expands in low-volatility regimes and contracts in high-volatility regimes, improving responsiveness.

Parameters:
  • data (Series) – Price series (typically close).

  • base_period (int, default: 14) – Base RSI period.

  • vol_period (int, default: 10) – Period for the volatility (standard deviation) calculation.

  • min_period (int, default: 5) – Minimum allowed RSI period.

  • max_period (int, default: 50) – Maximum allowed RSI period.

Returns:

Adaptive RSI values in [0, 100].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> close = pd.Series(100 + np.cumsum(np.random.randn(200) * 0.5))
>>> adaptive_rsi(close)
relative_strength(data, benchmark)[source]

Relative strength ratio of one series to another.

Commonly used for pair analysis or sector rotation. A rising ratio indicates data is outperforming benchmark.

Parameters:
  • data (Series) – Numerator price series (e.g., individual stock).

  • benchmark (Series) – Denominator price series (e.g., index or sector ETF).

Returns:

Ratio of data / benchmark.

Return type:

Series

Example

>>> import pandas as pd
>>> stock = pd.Series([100, 105, 110, 108, 112], dtype=float)
>>> index = pd.Series([1000, 1010, 1005, 1015, 1020], dtype=float)
>>> relative_strength(stock, index)
linear_regression_forecast(data, period=20, forecast_bars=1)[source]

Rolling linear regression forecast N bars ahead.

Fits a linear regression over each rolling window and projects the value forecast_bars steps beyond the last observation in the window.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Rolling window length for the regression.

  • forecast_bars (int, default: 1) – Number of bars ahead to forecast.

Returns:

Forecasted values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) * 0.5)
>>> linear_regression_forecast(close, period=20, forecast_bars=1)
standard_error_bands(data, period=20, num_bands=3)[source]

Linear regression line with standard error bands.

Fits a rolling linear regression and constructs bands at +-1, +-2, and +-3 standard errors (configurable via num_bands).

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Rolling window length.

  • num_bands (int, default: 3) – Number of band levels (1, 2, … num_bands standard errors).

Returns:

middle plus upper_N and lower_N for each band level N from 1 to num_bands.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) * 0.5)
>>> result = standard_error_bands(close, period=20)
r_squared_indicator(data, period=14)[source]

Rolling R-squared of linear regression as a trend strength measure.

An R-squared near 1.0 indicates prices are moving in a strong linear trend; near 0.0 indicates choppy, non-trending movement.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – Rolling window length for the regression.

Returns:

R-squared values in [0, 1].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) * 0.5)
>>> r_squared_indicator(close, period=14)
polynomial_regression(data, period=20, degree=2)[source]

Rolling polynomial regression fitted values.

Fits a polynomial of the given degree over each rolling window and returns the fitted value at the end of the window.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Rolling window length.

  • degree (int, default: 2) – Polynomial degree (2 = quadratic, 3 = cubic).

Returns:

Fitted polynomial values at the end of each window.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) ** 1.5 * 0.01)
>>> polynomial_regression(close, period=20, degree=2)
raff_regression_channel(data, period=50)[source]

Raff regression channel using maximum deviation.

Fits a rolling linear regression and constructs channel lines using the maximum absolute deviation of any point in the window from the regression line.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 50) – Rolling window length.

Returns:

center (regression line), upper, lower.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(80, dtype=float) * 0.5)
>>> result = raff_regression_channel(close, period=50)
detrended_regression(data, period=20)[source]

Residuals from rolling linear regression (for mean reversion).

Fits a rolling linear regression and returns the residual (actual minus predicted) at the end of each window. Positive values indicate price above trend; negative below trend.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Rolling window length.

Returns:

Detrended (residual) values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) * 0.5)
>>> detrended_regression(close, period=20)
fibonacci_retracements(swing_high, swing_low, direction='up')[source]

Compute Fibonacci retracement levels from a swing high/low pair.

Given a swing high and swing low, computes the standard Fibonacci retracement levels at 23.6%, 38.2%, 50%, 61.8%, and 78.6%.

Interpretation:
  • 23.6%: Shallow retracement – strong trend continuation likely. Common in fast-moving markets.

  • 38.2%: Moderate retracement – healthy pullback in a strong trend.

  • 50%: Not a Fibonacci ratio but widely watched. A 50% retracement is considered normal.

  • 61.8%: The “golden ratio” – the most important level. If price holds here, the trend is likely to resume.

  • 78.6%: Deep retracement – the trend is under pressure. If this level breaks, the trend may be over.

Trading rules:
  • Look for buy signals (candlestick patterns, divergence) at 38.2%-61.8% retracement levels in an uptrend.

  • Place stops below the 78.6% level.

  • The stronger the trend, the shallower the retracement (23.6%-38.2%).

Parameters:
  • swing_high (float) – The swing high price.

  • swing_low (float) – The swing low price.

  • direction (str, default: 'up') – If "up", retracements are measured from the high downward (pullback in an uptrend). If "down", retracements are measured from the low upward (pullback in a downtrend).

Returns:

Level names (e.g. "23.6%") as keys and price values.

Return type:

dict[str, float]

Example

>>> result = fibonacci_retracements(swing_high=110.0, swing_low=100.0)
>>> result["50.0%"]
105.0
fibonacci_extensions(swing_low, swing_high, pullback_low)[source]

Compute Fibonacci extension levels from three price points.

Uses a swing low, swing high, and pullback low to project extension levels at 100%, 127.2%, 161.8%, 200%, and 261.8%.

Interpretation:
  • Extension levels project where price might go AFTER a retracement completes.

  • 100%: The most common initial target (move equals the first swing).

  • 127.2%: Common target for corrective waves.

  • 161.8%: The golden extension – a key profit target.

  • 200% and 261.8%: Extended targets for strong trends.

  • Use for setting profit targets and identifying potential resistance levels in a trend.

Parameters:
  • swing_low (float) – The initial swing low price.

  • swing_high (float) – The swing high price.

  • pullback_low (float) – The pullback low price (retracement point).

Returns:

Extension level names as keys and projected price values.

Return type:

dict[str, float]

Example

>>> result = fibonacci_extensions(100.0, 110.0, 105.0)
>>> result["100.0%"]
115.0
fibonacci_fans(pivot_x, pivot_y, target_x, target_y)[source]

Compute Fibonacci fan line slopes from two pivot points.

Draws fan lines from (pivot_x, pivot_y) through Fibonacci retracement levels of the vertical distance to (target_x, target_y).

Parameters:
  • pivot_x (int) – Bar index of the pivot (start) point.

  • pivot_y (float) – Price at the pivot point.

  • target_x (int) – Bar index of the target (end) point.

  • target_y (float) – Price at the target point.

Returns:

Fan line labels as keys and slope values.

Return type:

dict[str, float]

Example

>>> result = fibonacci_fans(0, 100.0, 10, 110.0)
>>> abs(result["50.0%"] - 0.5) < 1e-10
True
fibonacci_time_zones(start_index, max_index)[source]

Compute Fibonacci time zone indices from a start bar.

Generates a sequence of bar indices at Fibonacci intervals (1, 1, 2, 3, 5, 8, 13, 21, …) from the given start index, up to max_index.

Parameters:
  • start_index (int) – The bar index to begin the Fibonacci time zones from.

  • max_index (int) – The maximum bar index (exclusive) to generate zones up to.

Returns:

List of bar indices at Fibonacci time intervals.

Return type:

list[int]

Example

>>> fibonacci_time_zones(0, 50)
[1, 2, 3, 5, 8, 13, 21, 34]
fibonacci_pivot_points(high, low, close)[source]

Pivot points using Fibonacci ratios.

Computes the standard pivot P = (H + L + C) / 3 and derives support/resistance using Fibonacci ratios applied to the prior bar’s range.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

Returns:

pivot, s1, s2, s3, r1, r2, r3.

Return type:

dict[str, Series]

Example

>>> import pandas as pd
>>> h = pd.Series([12, 13, 14, 13, 12], dtype=float)
>>> lo = pd.Series([10, 11, 12, 11, 10], dtype=float)
>>> c = pd.Series([11, 12, 13, 12, 11], dtype=float)
>>> result = fibonacci_pivot_points(h, lo, c)
auto_fibonacci(data, lookback=50, direction='up')[source]

Automatically detect swing high/low and compute Fibonacci retracements.

Scans the most recent lookback bars to find the highest high and lowest low, then computes Fibonacci retracement levels.

Parameters:
  • data (Series) – Price series (typically close).

  • lookback (int, default: 50) – Number of recent bars to scan for swing points.

  • direction (str, default: 'up') – Trend direction assumption: "up" retraces from high downward, "down" retraces from low upward.

Returns:

swing_high (float), swing_high_idx (index label), swing_low (float), swing_low_idx (index label), levels (dict of retracement levels).

Return type:

dict[str, object]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> close = pd.Series(100 + np.cumsum(np.random.randn(100) * 0.5))
>>> result = auto_fibonacci(close, lookback=30)
alma(data, period=9, offset=0.85, sigma=6.0)[source]

Arnaud Legoux Moving Average (ALMA).

A Gaussian-weighted moving average that allows the user to control the position of the bell curve along the window via offset and the width via sigma.

Interpretation:
  • Price above ALMA: Bullish.

  • Price below ALMA: Bearish.

  • Combines the responsiveness of EMA with the smoothness of Gaussian weighting. The offset parameter lets you place more weight on recent prices (offset near 1) or older prices (offset near 0).

  • Excellent alternative to EMA for crossover systems.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 9) – Window length.

  • offset (float, default: 0.85) – Controls the position of the Gaussian peak within the window. 0 = far left (oldest), 1 = far right (newest).

  • sigma (float, default: 6.0) – Controls the width of the Gaussian bell curve. Higher values produce a broader, smoother curve.

Returns:

ALMA values. The first period - 1 entries are NaN.

Return type:

Series

Example

>>> result = alma(close, period=9, offset=0.85, sigma=6.0)
lsma(data, period=25)[source]

Least Squares Moving Average (LSMA).

Also known as the Linear Regression Value or End Point Moving Average. At each bar, a least-squares line is fit over the window and the endpoint of the line is returned.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 25) – Window length for the linear regression.

Returns:

LSMA values.

Return type:

Series

Example

>>> result = lsma(close, period=25)
swma(data)[source]

Symmetrically Weighted Moving Average (SWMA).

A 4-bar weighted average using weights [1, 2, 2, 1] / 6.

Parameters:

data (Series) – Price series.

Returns:

SWMA values. The first 3 entries are NaN.

Return type:

Series

Example

>>> result = swma(close)
sinema(data, period=14)[source]

Sine-Weighted Moving Average.

Each element in the window is weighted by the sine of its proportional position within a half-period (pi), giving the most weight to the center of the window.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Window length.

Returns:

Sine-weighted moving average values.

Return type:

Series

Example

>>> result = sinema(close, period=14)
trima(data, period=20)[source]

Triangular Moving Average (TRIMA).

Equivalent to a double SMA: SMA(SMA(data, ceil((period+1)/2)), floor((period+1)/2)). This produces a smoother curve than a single SMA by effectively giving the most weight to the center of the window.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Overall window length.

Returns:

TRIMA values.

Return type:

Series

Example

>>> result = trima(close, period=20)
jma(data, period=7, phase=50.0, power=2)[source]

Jurik Moving Average approximation (JMA).

An adaptive moving average that attempts to minimize lag and overshoot. This is an approximation of the proprietary Jurik algorithm using an adaptive EMA with phase and power controls.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 7) – Smoothing period.

  • phase (float, default: 50.0) – Phase parameter in the range [-100, 100]. Controls the tradeoff between lag and overshoot. 0 is balanced, positive reduces lag.

  • power (int, default: 2) – Power parameter controlling the smoothing curve shape.

Returns:

JMA values.

Return type:

Series

Example

>>> result = jma(close, period=7, phase=50, power=2)
gaussian_filter(data, period=14, poles=2)[source]

Gaussian-weighted rolling filter.

Applies a discrete Gaussian kernel over the rolling window. The standard deviation of the kernel is set to period / 4 so that the window captures approximately two standard deviations.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Window length.

  • poles (int, default: 2) – Number of standard deviations captured within the window. Used to set sigma = period / (2 * poles).

Returns:

Gaussian-filtered values.

Return type:

Series

Example

>>> result = gaussian_filter(close, period=14)
butterworth_filter(data, period=14)[source]

2nd-order Butterworth low-pass filter (IIR).

This implements the classic Ehlers two-pole Butterworth filter, which provides smooth output with minimal lag relative to its degree of smoothing.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Cut-off period in bars.

Returns:

Butterworth-filtered values.

Return type:

Series

Example

>>> result = butterworth_filter(close, period=14)
supersmoother(data, period=14)[source]

Ehlers Super Smoother (2-pole Butterworth variant).

A modified Butterworth filter by John Ehlers that removes aliasing noise while retaining a smooth, low-lag response.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Cut-off period in bars.

Returns:

Super-smoothed values.

Return type:

Series

Example

>>> result = supersmoother(close, period=14)
hann_window_ma(data, period=14)[source]

Hann (raised cosine) windowed moving average.

Each element in the window is weighted by the Hann function: w(i) = 0.5 * (1 - cos(2 * pi * i / (N - 1)))

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Window length.

Returns:

Hann-windowed moving average values.

Return type:

Series

Example

>>> result = hann_window_ma(close, period=14)
hamming_window_ma(data, period=14)[source]

Hamming windowed moving average.

Each element in the window is weighted by the Hamming function: w(i) = 0.54 - 0.46 * cos(2 * pi * i / (N - 1))

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Window length.

Returns:

Hamming-windowed moving average values.

Return type:

Series

Example

>>> result = hamming_window_ma(close, period=14)
kaufman_efficiency_ratio(data, period=10)[source]

Kaufman Efficiency Ratio (ER).

Measures the efficiency of price movement as the ratio of directional change to total path length. This is the core component of the Kaufman Adaptive Moving Average (KAMA).

ER = |close - close[period]| / sum(|close - close[1]|, period)

Values near 1.0 indicate strong trending; values near 0.0 indicate choppy / mean-reverting markets.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – Look-back period.

Returns:

Efficiency ratio values in [0, 1].

Return type:

Series

Example

>>> result = kaufman_efficiency_ratio(close, period=10)
choppiness_index(high, low, close, period=14)[source]

Choppiness Index.

Measures whether the market is trending or range-bound.

Interpretation:
  • > 61.8: Choppy / range-bound market. Avoid trend-following strategies; use mean-reversion instead.

  • < 38.2: Strong trending market. Use trend-following strategies; avoid mean-reversion.

  • 38.2-61.8: Transitional zone.

  • Does NOT indicate trend direction, only whether a trend exists.

  • Low choppiness often precedes a breakout.

Trading rules:
  • Apply trend strategies when CI < 38.2.

  • Apply range strategies when CI > 61.8.

  • Wait for CI to drop before entering breakout trades.

CI = 100 * log10(sum(ATR(1), n) / (highest_high - lowest_low)) / log10(n)

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

Returns:

Choppiness Index values, typically in [0, 100].

Return type:

Series

Example

>>> result = choppiness_index(high, low, close, period=14)
random_walk_index(high, low, close, period=14)[source]

Random Walk Index (RWI).

Compares the range of directional price moves to the expected range of a random walk. Values above 1.0 suggest trending behavior.

Interpretation:
  • RWI High > 1: Upward price movement exceeds what a random walk would produce = genuine uptrend.

  • RWI Low > 1: Downward price movement exceeds random walk = genuine downtrend.

  • Both < 1: Price movement is consistent with random noise = no trend.

  • RWI High > RWI Low: Bullish bias.

  • RWI Low > RWI High: Bearish bias.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

Returns:

rwi_high and rwi_low.

Return type:

dict[str, Series]

Example

>>> result = random_walk_index(high, low, close, period=14)
>>> result["rwi_high"]
polarized_fractal_efficiency(close, period=10, smoothing=5)[source]

Polarized Fractal Efficiency (PFE).

Measures the efficiency of the price path using fractal geometry. A straight-line move yields +/- 100; a random walk yields ~0.

Interpretation:
  • > 0: Price is moving efficiently upward (trending up).

  • < 0: Price is moving efficiently downward (trending down).

  • Near 0: Choppy, inefficient movement (no trend).

  • > +50: Strong bullish trend.

  • < -50: Strong bearish trend.

  • Think of it as “how direct is the price path” – values near +/-100 mean a straight line, near 0 means a random walk.

PFE = sign(direction) * sqrt(sum_sq_diff + direction^2) / sum_single_diff * 100

The raw PFE is then smoothed with an EMA.

Parameters:
  • close (Series) – Close prices.

  • period (int, default: 10) – Look-back period.

  • smoothing (int, default: 5) – EMA smoothing period applied to the raw PFE.

Returns:

PFE values, bounded roughly in [-100, 100].

Return type:

Series

Example

>>> result = polarized_fractal_efficiency(close, period=10)
price_zone_oscillator(close, period=14)[source]

Price Zone Oscillator (PZO).

An EMA-based oscillator that classifies price action into zones. A positive close change gets +close, negative gets -close.

PZO = 100 * EMA(signed_close, period) / EMA(close, period)

Parameters:
  • close (Series) – Close prices.

  • period (int, default: 14) – EMA period.

Returns:

PZO values, typically in [-100, 100].

Return type:

Series

Example

>>> result = price_zone_oscillator(close, period=14)
ergodic_oscillator(close, fast=5, slow=20, signal=5)[source]

Ergodic Oscillator.

A True Strength Index variant that produces a histogram (oscillator minus signal line) for identifying momentum shifts.

Parameters:
  • close (Series) – Close prices.

  • fast (int, default: 5) – Fast double-smoothing EMA period.

  • slow (int, default: 20) – Slow double-smoothing EMA period.

  • signal (int, default: 5) – Signal line EMA period.

Returns:

ergodic (the TSI line), signal, and histogram.

Return type:

dict[str, Series]

Example

>>> result = ergodic_oscillator(close)
>>> result["ergodic"]
elder_thermometer(high, low, period=22)[source]

Elder Thermometer.

Measures the distance of the current bar from the previous bar’s range, indicating how far price has moved beyond the prior bar.

Thermo = max(high - prev_high, prev_low - low, 0)

The result is smoothed with an EMA.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 22) – EMA smoothing period.

Returns:

Elder Thermometer values (non-negative).

Return type:

Series

Example

>>> result = elder_thermometer(high, low, period=22)
market_facilitation_index(high, low, volume)[source]

Market Facilitation Index (MFI / BW MFI).

Also known as the Bill Williams Market Facilitation Index. Measures the efficiency of price movement per unit of volume.

MFI = (high - low) / volume

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • volume (Series) – Volume data.

Returns:

Market Facilitation Index values.

Return type:

Series

Example

>>> result = market_facilitation_index(high, low, volume)
efficiency_ratio(data, period=10)[source]

Efficiency Ratio (ER).

Measures the efficiency of price movement as the ratio of net directional change to the total path traveled.

ER = |close - close[n]| / sum(|close - close[1]|, n)

Values near 1.0 indicate a strong trend; values near 0.0 indicate choppy, range-bound price action.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 10) – Look-back period.

Returns:

Efficiency ratio values in [0, 1].

Return type:

Series

Example

>>> result = efficiency_ratio(close, period=10)
trend_intensity_index(data, period=30)[source]

Trend Intensity Index (TII).

Measures the percentage of closes above or below the SMA over the look-back period.

TII = 100 * (count_above - count_below) / period

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 30) – Look-back period.

Returns:

TII values in [-100, 100]. Positive indicates bullish bias; negative indicates bearish bias.

Return type:

Series

Example

>>> result = trend_intensity_index(close, period=30)
directional_movement_index(high, low, close, period=14)[source]

Simplified Directional Movement Index (DMI).

Computes +DI and -DI without the full ADX smoothing, providing raw directional movement readings.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Smoothing period.

Returns:

plus_di (+DI) and minus_di (-DI), both in [0, 100].

Return type:

dict[str, Series]

Example

>>> result = directional_movement_index(high, low, close, period=14)
>>> result["plus_di"]
kairi(data, period=14)[source]

KAIRI — percentage deviation from the SMA.

KAIRI = ((close - SMA(close, period)) / SMA(close, period)) * 100

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – SMA period.

Returns:

KAIRI values (percentage, unbounded).

Return type:

Series

Example

>>> result = kairi(close, period=14)
gopalakrishnan_range(high, low, period=5)[source]

Gopalakrishnan Range Index (GAPO).

GAPO = log(max_high - min_low) / log(period)

Measures the log of the high-low range relative to the log of the look-back period. Higher values indicate larger ranges.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 5) – Look-back period.

Returns:

GAPO values (non-negative).

Return type:

Series

Example

>>> result = gopalakrishnan_range(high, low, period=5)
pretty_good_oscillator(high, low, close, period=14)[source]

Pretty Good Oscillator (PGO).

PGO = (close - SMA(close, period)) / ATR(period)

Normalizes the deviation from the SMA by the ATR, producing a volatility-adjusted momentum reading.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – SMA / ATR period.

Returns:

PGO values (unbounded).

Return type:

Series

Example

>>> result = pretty_good_oscillator(high, low, close, period=14)
connors_tps(data, period=2)[source]

ConnorsRSI TPS component — cumulative streak RSI.

Computes an up/down streak series, then applies RSI to the streak values. This isolates the streak component of ConnorsRSI.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 2) – RSI period applied to the streak series.

Returns:

Streak RSI values in [0, 100].

Return type:

Series

Example

>>> result = connors_tps(close, period=2)
relative_momentum_index(data, period=14, momentum_period=4)[source]

Relative Momentum Index (RMI).

RSI applied to momentum (close - close[momentum_period]) instead of the simple one-bar change. This produces a smoother oscillator that reacts to the direction and magnitude of price swings over momentum_period bars.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – RSI smoothing period.

  • momentum_period (int, default: 4) – Look-back for the momentum (difference) calculation.

Returns:

RMI values in [0, 100].

Return type:

Series

Example

>>> result = relative_momentum_index(close, period=14, momentum_period=4)
find_support_resistance(high, low, lookback=5, num_levels=5, tolerance=0.02)[source]

Detect horizontal support and resistance levels via clustering.

Identifies local swing highs and swing lows, then clusters nearby levels within tolerance (as a fraction of price) to produce consolidated S/R levels.

Interpretation:
  • Support levels: Prices where buying pressure historically prevented further decline. Price tends to bounce at these levels.

  • Resistance levels: Prices where selling pressure historically prevented further advance.

  • Multiple touches: A level tested many times is stronger.

  • Breakout through resistance: Resistance becomes support (role reversal) and vice versa.

Trading rules:
  • Buy at support levels with confirmation (candlestick pattern, volume spike).

  • Sell at resistance levels with confirmation.

  • Place stops on the other side of the S/R level.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • lookback (int, default: 5) – Number of bars on each side to confirm a swing point.

  • num_levels (int, default: 5) – Maximum number of S/R levels to return per side.

  • tolerance (float, default: 0.02) – Fraction of price within which nearby levels are merged.

Returns:

support and resistance lists of price levels, sorted ascending.

Return type:

dict[str, list[float]]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(200) * 0.5) + 1)
>>> lo = h - 2
>>> result = find_support_resistance(h, lo)
price_clustering(data, num_levels=5, bins=100)[source]

Find price levels where price has spent the most time.

Builds a histogram of price values and returns the bin centres with the highest counts, analogous to a simplified volume profile.

Parameters:
  • data (Series) – Price series (typically close).

  • num_levels (int, default: 5) – Number of key price levels to return.

  • bins (int, default: 100) – Number of histogram bins.

Returns:

Array of key price levels sorted ascending.

Return type:

ndarray

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series([100, 101, 100, 99, 100, 101, 102, 100], dtype=float)
>>> price_clustering(close, num_levels=3)
fractal_levels(high, low, period=2)[source]

Williams fractal swing high/low identification.

An up-fractal occurs when the high is the highest of 2 * period + 1 bars. A down-fractal occurs when the low is the lowest.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 2) – Number of bars on each side of the fractal pivot.

Returns:

up_fractals (boolean Series, True at up-fractal bars), down_fractals (boolean Series, True at down-fractal bars).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(50) * 0.5) + 1)
>>> lo = h - 2
>>> result = fractal_levels(h, lo, period=2)
round_number_levels(current_price, num_levels=5, step=None)[source]

Generate psychological round number levels near the current price.

Computes evenly spaced round numbers above and below the given price. Useful for identifying potential support/resistance at psychologically significant prices.

Parameters:
  • current_price (float) – The current (or reference) price.

  • num_levels (int, default: 5) – Number of levels to return on each side (above and below).

  • step (float | None, default: None) – Step size between levels. If None, automatically determined from the magnitude of current_price.

Returns:

Sorted list of round number price levels.

Return type:

list[float]

Example

>>> round_number_levels(105.3, num_levels=3, step=10.0)
[80.0, 90.0, 100.0, 110.0, 120.0, 130.0]
supply_demand_zones(open_, high, low, close, body_pct=0.6, consolidation_bars=3)[source]

Detect supply and demand zones from price action.

A demand zone forms when a large bullish candle follows a period of basing (small bodies). A supply zone forms similarly for bearish moves. Zones are defined by the basing candles’ range.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_pct (float, default: 0.6) – Minimum body-to-range ratio to qualify as a “large” candle.

  • consolidation_bars (int, default: 3) – Number of preceding small-body bars required for basing.

  • open_ (Series)

Returns:

demand and supply lists, each containing dicts with zone_low, zone_high, and index keys.

Return type:

dict[str, list[dict[str, float]]]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> n = 100
>>> c = pd.Series(100 + np.cumsum(np.random.randn(n) * 0.5))
>>> o = c.shift(1).fillna(c.iloc[0])
>>> h = pd.concat([o, c], axis=1).max(axis=1) + 0.5
>>> lo = pd.concat([o, c], axis=1).min(axis=1) - 0.5
>>> result = supply_demand_zones(o, h, lo, c)
Parameters:
Return type:

dict[str, list[dict[str, float]]]

trendline_detection(high, low, lookback=5, min_touches=2)[source]

Fit linear trendlines to swing high and swing low points.

Detects swing points, then fits lines through the most recent swing highs (resistance trendline) and swing lows (support trendline) using least-squares regression.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • lookback (int, default: 5) – Number of bars on each side for swing point detection.

  • min_touches (int, default: 2) – Minimum number of swing points required to fit a trendline.

Returns:

resistance_lines and support_lines, each containing dicts with slope, intercept, and num_touches keys.

Return type:

dict[str, list[dict[str, float]]]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(100) * 0.5) + 1)
>>> lo = h - 2
>>> result = trendline_detection(h, lo, lookback=5)

Overlap Studies

Moving averages, bands, and channel studies drawn on the price chart.

Overlap / moving average technical analysis studies.

This module provides a comprehensive set of moving average and overlay indicators used in technical analysis. All functions accept pd.Series inputs and return pd.Series (or dict[str, pd.Series] for multi-output indicators).

sma(data, period=20)[source]

Simple Moving Average.

The most fundamental overlay indicator. Smooths price by averaging the last period values equally.

Interpretation:
  • Price above SMA: Bullish – price is above its average.

  • Price below SMA: Bearish – price is below its average.

  • Golden cross: Short-term SMA (e.g. 50) crosses above long-term SMA (e.g. 200) = bullish trend signal.

  • Death cross: Short-term SMA crosses below long-term SMA = bearish trend signal.

  • Slope: Rising SMA confirms uptrend; falling confirms downtrend.

  • Common periods: 20 (short-term), 50 (medium-term), 200 (long-term institutional benchmark).

Trading rules:
  • Buy when price crosses above SMA (or when shorter SMA crosses above longer SMA).

  • Sell when price crosses below SMA.

  • Use 200 SMA as a trend filter: only take longs above it.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Window length.

Returns:

Simple moving average values. The first period - 1 entries are NaN.

Return type:

Series

ema(data, period=20)[source]

Exponential Moving Average.

Uses the standard span-based smoothing factor 2 / (period + 1). More responsive to recent price changes than SMA because it weights recent data more heavily.

Interpretation:
  • Same as SMA: price above = bullish, price below = bearish.

  • More responsive than SMA: catches trend changes faster but may produce more whipsaws.

  • EMA crossovers (e.g. 12/26 EMA) form the basis of MACD.

  • Common periods: 9 (very short-term), 21 (swing trading), 50 and 200 (institutional benchmarks).

Trading rules:
  • Same crossover rules as SMA but with faster signals.

  • In fast markets, prefer EMA over SMA for tighter stops and quicker entries.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Span for the EMA.

Returns:

Exponential moving average values.

Return type:

Series

wma(data, period=20)[source]

Weighted Moving Average.

Weights increase linearly so that the most recent observation receives the highest weight. A compromise between SMA and EMA.

Interpretation:
  • Same directional signals as SMA/EMA: price above = bullish, below = bearish, crossovers for entry/exit.

  • More responsive than SMA but less than EMA.

  • Useful when you want more weight on recent data but a smoother result than EMA.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Window length.

Returns:

Weighted moving average values.

Return type:

Series

dema(data, period=20)[source]

Double Exponential Moving Average.

DEMA = 2 * EMA(data) - EMA(EMA(data))

Reduces the lag inherent in a standard EMA by subtracting a double-smoothed version. More responsive to recent price changes.

Interpretation:
  • Same as EMA/SMA but with reduced lag. Use for faster crossover signals and tighter trailing stops.

  • Price above DEMA = bullish; below = bearish.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Span for each EMA component.

Returns:

DEMA values.

Return type:

Series

tema(data, period=20)[source]

Triple Exponential Moving Average.

TEMA = 3 * EMA - 3 * EMA(EMA) + EMA(EMA(EMA))

Even less lag than DEMA. Hugs price very tightly and reacts quickly to changes. Can overshoot in choppy markets.

Interpretation:
  • Same as EMA but with minimal lag. Excellent for short-term trend following but may whipsaw in consolidation.

  • Price above TEMA = bullish; below = bearish.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Span for each EMA component.

Returns:

TEMA values.

Return type:

Series

kama(data, period=10, fast=2, slow=30)[source]

Kaufman Adaptive Moving Average (KAMA).

KAMA adapts its smoothing constant based on the efficiency ratio of the price movement. In trending markets it acts like a fast EMA; in choppy markets it slows down to avoid whipsaws.

Interpretation:
  • Price above KAMA: Bullish.

  • Price below KAMA: Bearish.

  • Flat KAMA: Market is choppy/range-bound (KAMA stops following noise). This is the key advantage over SMA/EMA.

  • KAMA direction change: Potential trend reversal signal.

Trading rules:
  • Buy when price crosses above KAMA.

  • Sell when price crosses below KAMA.

  • KAMA’s adaptive nature makes it better for trend following than fixed-period moving averages in volatile markets.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – Efficiency ratio look-back period.

  • fast (int, default: 2) – Fast smoothing constant period.

  • slow (int, default: 30) – Slow smoothing constant period.

Returns:

KAMA values.

Return type:

Series

vwap(high, low, close, volume)[source]

Volume Weighted Average Price (VWAP).

Computed as the cumulative sum of typical_price * volume divided by cumulative volume. This is the intraday running VWAP; for session-reset VWAP, pre-group your data by session.

Interpretation:
  • Price above VWAP: Buyers are in control; longs entered at good prices relative to the average fill.

  • Price below VWAP: Sellers are in control.

  • VWAP as support/resistance: Institutional traders use VWAP as a benchmark. Price tends to gravitate toward VWAP.

  • Mean reversion: Extreme deviations from VWAP tend to revert, especially intraday.

Trading rules:
  • Buy pullbacks to VWAP in an uptrend (institutional support).

  • Sell rallies to VWAP in a downtrend (institutional resistance).

  • Institutions aim to buy below VWAP and sell above it; track whether your fills are better than VWAP.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

Cumulative VWAP values.

Return type:

Series

supertrend(high, low, close, period=10, multiplier=3.0)[source]

Supertrend indicator.

A trend-following overlay that flips between support and resistance levels based on ATR bands. One of the cleanest trend indicators.

Interpretation:
  • Direction = 1 (uptrend): Supertrend line acts as dynamic support below price. Trend is bullish.

  • Direction = -1 (downtrend): Supertrend line acts as dynamic resistance above price. Trend is bearish.

  • Flip from -1 to 1: Buy signal (trend turns bullish).

  • Flip from 1 to -1: Sell signal (trend turns bearish).

Trading rules:
  • Buy when direction flips to 1 (close above supertrend).

  • Sell when direction flips to -1 (close below supertrend).

  • Use the supertrend line as a trailing stop.

  • Higher multiplier = fewer flips but wider stops.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 10) – ATR look-back period.

  • multiplier (float, default: 3.0) – ATR multiplier for bands.

Returns:

supertrend — the indicator line, and direction (1 for uptrend / bullish, -1 for downtrend / bearish).

Return type:

dict[str, Series]

ichimoku(high, low, close, tenkan=9, kijun=26, senkou_b=52)[source]

Ichimoku Kinko Hyo (Ichimoku Cloud).

A comprehensive trend system that provides support/resistance, trend direction, and momentum in a single view.

Interpretation:
  • Price above cloud: Bullish trend. The cloud acts as support.

  • Price below cloud: Bearish trend. The cloud acts as resistance.

  • Price inside cloud: Trend is transitioning/uncertain.

  • Tenkan-Kijun cross: Tenkan crossing above Kijun = bullish signal (TK cross). Below = bearish.

  • Senkou Span A above B: Cloud is green = bullish bias.

  • Senkou Span A below B: Cloud is red = bearish bias.

  • Chikou Span above price: Confirms bullish momentum.

  • Cloud thickness: Thicker cloud = stronger support/ resistance.

Trading rules:
  • Buy when price breaks above cloud AND Tenkan > Kijun AND Chikou is above price from 26 periods ago.

  • Sell when price breaks below cloud AND Tenkan < Kijun.

  • Use cloud edges (Senkou A/B) as stop-loss levels.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tenkan (int, default: 9) – Tenkan-sen (conversion line) period.

  • kijun (int, default: 26) – Kijun-sen (base line) period.

  • senkou_b (int, default: 52) – Senkou Span B period.

Returns:

Keys: tenkan_sen, kijun_sen, senkou_span_a, senkou_span_b, chikou_span.

Return type:

dict[str, Series]

Notes

Senkou Span A and B are shifted forward by kijun periods, and the Chikou Span is shifted backward by kijun periods, matching traditional charting convention.

bollinger_bands(data, period=20, std_dev=2.0)[source]

Bollinger Bands.

A volatility-based envelope around a moving average. The bands widen during high volatility and contract during low volatility.

Interpretation:
  • Price touching upper band: Price is at the high end of its recent range. Not necessarily a sell signal in strong uptrends (walking the band).

  • Price touching lower band: Price is at the low end. Not necessarily a buy signal in downtrends.

  • Squeeze (narrow bandwidth): Low volatility – a breakout in either direction is imminent.

  • Expansion (wide bandwidth): High volatility – move may be overextended and due for consolidation.

  • %B > 1: Price is above the upper band.

  • %B < 0: Price is below the lower band.

  • %B near 0.5: Price is at the middle band (SMA).

Trading rules:
  • Mean reversion: Buy at lower band, sell at upper band (works best in ranging markets).

  • Breakout: Buy on a close above upper band with expanding bandwidth (works in trending markets).

  • Squeeze play: Wait for narrow bands, then trade the breakout direction.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – SMA window length.

  • std_dev (float, default: 2.0) – Number of standard deviations for the bands.

Returns:

upper, middle, lower, bandwidth, percent_b.

Return type:

dict[str, Series]

keltner_channel(high, low, close, period=20, multiplier=1.5)[source]

Keltner Channel.

The middle line is an EMA of the close; upper and lower bands are offset by a multiple of the Average True Range.

Interpretation:
  • Price above upper band: Strong uptrend or overbought.

  • Price below lower band: Strong downtrend or oversold.

  • Price bouncing off middle line: EMA acting as support (uptrend) or resistance (downtrend).

  • Keltner + Bollinger: When BB is inside KC, a “squeeze” is active. See squeeze_momentum().

Trading rules:
  • Buy pullbacks to the middle line (EMA) in an uptrend.

  • Sell rallies to the middle line in a downtrend.

  • Breakout above upper band = trend continuation (go long).

  • Breakout below lower band = trend continuation (go short).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – EMA / ATR period.

  • multiplier (float, default: 1.5) – ATR multiplier.

Returns:

upper, middle, lower.

Return type:

dict[str, Series]

donchian_channel(high, low, period=20)[source]

Donchian Channel.

The simplest channel indicator: the highest high and lowest low over the look-back period. The basis of the Turtle Trading system.

Interpretation:
  • Price at upper band: Price is at the highest point in period bars = potential breakout to the upside.

  • Price at lower band: Price is at the lowest point = potential breakout to the downside.

  • Channel width: Wider channel = more volatile market.

  • Middle line: Average of upper and lower = equilibrium.

Trading rules:
  • Buy when price breaks above the upper band (20-day high).

  • Sell when price breaks below the lower band (20-day low).

  • Use 10-day Donchian for exits, 20-day for entries (Turtle Trading system).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 20) – Look-back period.

Returns:

upper, lower, middle.

Return type:

dict[str, Series]

Momentum Indicators

Oscillators measuring speed and magnitude of price changes.

Momentum oscillator indicators.

This module contains oscillators that measure the speed and magnitude of price movements. All functions accept pd.Series inputs and return pd.Series (or dict[str, pd.Series] for multi-output indicators).

rsi(data, period=14)[source]

Relative Strength Index (RSI).

Measures the speed and magnitude of recent price changes to evaluate overbought or oversold conditions. Uses the Wilder smoothing method (equivalent to ewm(alpha=1/period)).

RSI = 100 - (100 / (1 + RS)) where RS = avg_gain / avg_loss over period bars.

Interpretation:
  • > 70: Overbought – price may be due for a pullback. In strong uptrends, RSI can stay above 70 for extended periods.

  • 30-70: Neutral zone.

  • < 30: Oversold – price may be due for a bounce. In strong downtrends, RSI can stay below 30 for extended periods.

  • Divergence: If price makes a new high but RSI does not, bearish divergence signals weakening momentum. Conversely, bullish divergence when price makes a new low but RSI does not.

  • Centerline crossover: RSI crossing above 50 = bullish shift, below 50 = bearish shift.

Trading rules:
  • Buy when RSI crosses above 30 (oversold bounce).

  • Sell when RSI crosses below 70 (overbought reversal).

  • Use divergences for higher-probability signals.

  • Adjust thresholds in trending markets (80/20 instead of 70/30).

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – Look-back period. 14 is standard. Shorter = more sensitive, longer = smoother. Use 9 for short-term, 25 for long-term.

Returns:

RSI values in the range [0, 100].

Return type:

Series

stochastic(high, low, close, k_period=14, d_period=3)[source]

Stochastic Oscillator (%K / %D).

Measures where the close sits within the recent high-low range. When %K is near 100, price closed near the top of the range (bullish); near 0, it closed near the bottom (bearish).

Interpretation:
  • > 80: Overbought zone. In strong uptrends, the indicator can stay above 80 for extended periods without signaling a top.

  • < 20: Oversold zone. In strong downtrends, can persist.

  • %K crosses above %D below 20: Bullish crossover buy signal.

  • %K crosses below %D above 80: Bearish crossover sell signal.

  • Divergence: Price makes new high but %K does not = bearish.

Trading rules:
  • Buy when %K crosses above %D in the oversold zone (< 20).

  • Sell when %K crosses below %D in the overbought zone (> 80).

  • Avoid trading crossovers in the neutral zone (20-80) unless confirmed by other indicators.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • k_period (int, default: 14) – Look-back for %K.

  • d_period (int, default: 3) – SMA smoothing period for %D.

Returns:

k (%K) and d (%D), both in [0, 100].

Return type:

dict[str, Series]

stochastic_rsi(data, period=14, k_period=3, d_period=3)[source]

Stochastic RSI.

Applies the Stochastic formula to the RSI output, producing an even more sensitive oscillator. Useful for detecting short-term overbought/oversold conditions within the RSI itself.

Interpretation:
  • > 80: RSI is near its recent high – overbought.

  • < 20: RSI is near its recent low – oversold.

  • %K/%D crossovers: Same logic as standard Stochastic.

  • More volatile than standard Stochastic; best combined with a trend filter to avoid false signals in ranging markets.

Trading rules:
  • Buy when StochRSI crosses above 20 (oversold bounce).

  • Sell when StochRSI crosses below 80 (overbought reversal).

  • Combine with a trend indicator (e.g. 200 EMA) to filter signals in the direction of the prevailing trend.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – RSI period.

  • k_period (int, default: 3) – Smoothing for %K.

  • d_period (int, default: 3) – Smoothing for %D.

Returns:

k and d, both in [0, 100].

Return type:

dict[str, Series]

macd(data, fast=12, slow=26, signal=9)[source]

Moving Average Convergence Divergence (MACD).

Tracks the relationship between two EMAs. When the fast EMA pulls away from the slow EMA, momentum is strong. The signal line acts as a trigger for entries and exits.

Interpretation:
  • MACD above zero: Fast EMA > slow EMA = bullish momentum.

  • MACD below zero: Fast EMA < slow EMA = bearish momentum.

  • Signal line crossover: MACD crossing above its signal line is a bullish signal; crossing below is bearish.

  • Histogram: Represents the distance between MACD and signal. Growing bars = strengthening momentum. Shrinking bars = momentum fading (potential reversal ahead).

  • Divergence: Price makes a new high but MACD does not = bearish divergence. Price makes a new low but MACD does not = bullish divergence.

  • Zero-line crossover: MACD crossing above zero confirms an uptrend; crossing below confirms a downtrend.

Trading rules:
  • Buy when MACD crosses above signal line (bullish crossover).

  • Sell when MACD crosses below signal line (bearish crossover).

  • Histogram peak/trough reversals can provide early warnings.

  • Combine with price action for confirmation.

Parameters:
  • data (Series) – Price series.

  • fast (int, default: 12) – Fast EMA period.

  • slow (int, default: 26) – Slow EMA period.

  • signal (int, default: 9) – Signal EMA period.

Returns:

macd, signal, histogram.

Return type:

dict[str, Series]

williams_r(high, low, close, period=14)[source]

Williams %R.

Measures where the close is relative to the high-low range over the look-back period. Mathematically the inverse of the Stochastic %K, but on a [-100, 0] scale.

Interpretation:
  • -20 to 0: Overbought – close is near the period high.

  • -80 to -100: Oversold – close is near the period low.

  • -50 crossover: Crossing above -50 = bullish, below = bearish.

  • Note: Overbought does not mean sell immediately; in strong uptrends, Williams %R stays near 0 for extended periods.

Trading rules:
  • Buy when %R crosses above -80 (leaving oversold zone).

  • Sell when %R crosses below -20 (leaving overbought zone).

  • Use divergence between price and %R for reversal signals.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

Returns:

Williams %R values in [-100, 0].

Return type:

Series

cci(high, low, close, period=20)[source]

Commodity Channel Index (CCI).

Measures the deviation of the typical price from its moving average, normalized by mean deviation. Uses Lambert’s constant of 0.015 so that roughly 75% of values fall within [-100, +100].

Interpretation:
  • > +100: Price is unusually high relative to average – strong uptrend or overbought condition.

  • < -100: Price is unusually low – strong downtrend or oversold condition.

  • Zero-line crossover: CCI crossing above 0 indicates price is above its average (bullish); below 0 is bearish.

  • Divergence: Price makes new high but CCI does not = weakening momentum.

Trading rules:
  • Buy when CCI crosses above +100 (trend entry) or above 0 (conservative entry).

  • Sell when CCI crosses below -100 (trend entry) or below 0.

  • Exit longs when CCI crosses back below +100 from above.

  • Use +200/-200 for extreme overbought/oversold levels.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – Look-back period.

Returns:

CCI values (unbounded, typically between -300 and +300).

Return type:

Series

roc(data, period=10)[source]

Rate of Change (ROC) – percentage change over period bars.

Measures the percentage difference between the current price and the price period bars ago. A pure momentum measure.

Interpretation:
  • Positive: Price is higher than it was period bars ago.

  • Negative: Price is lower.

  • Zero-line crossover: Crossing above zero = bullish momentum shift; crossing below = bearish.

  • Extreme readings: Unusually high ROC may indicate an overextended move ripe for mean reversion.

Trading rules:
  • Buy when ROC crosses above zero from below.

  • Sell when ROC crosses below zero from above.

  • Use divergence with price for reversal signals.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – Look-back period.

Returns:

Percentage rate of change.

Return type:

Series

momentum(data, period=10)[source]

Price Momentum (difference over period bars).

The simplest momentum indicator: the absolute price change over the look-back window. Unlike ROC, this is not percentage-based, so it is scale-dependent.

Interpretation:
  • Positive: Price is rising relative to period bars ago.

  • Negative: Price is falling.

  • Zero-line crossover: Same as ROC – bullish above, bearish below.

  • Magnitude: Larger values = stronger momentum.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – Look-back period.

Returns:

Momentum values (price difference, not percentage).

Return type:

Series

tsi(data, long=25, short=13, signal=13)[source]

True Strength Index (TSI).

A double-smoothed momentum oscillator that measures the ratio of smoothed price change to smoothed absolute price change. Oscillates between -100 and +100.

Interpretation:
  • Above zero: Bullish momentum (price changes are predominantly positive).

  • Below zero: Bearish momentum.

  • Signal line crossover: TSI crossing above its signal line = bullish; crossing below = bearish.

  • Zero-line crossover: Confirms trend direction change.

  • Divergence: Price makes new high but TSI does not = bearish divergence (and vice versa).

Trading rules:
  • Buy when TSI crosses above zero or above its signal line.

  • Sell when TSI crosses below zero or below its signal line.

  • Use both zero-line and signal-line crossovers together for higher-confidence signals.

Parameters:
  • data (Series) – Price series.

  • long (int, default: 25) – Long EMA period.

  • short (int, default: 13) – Short EMA period.

  • signal (int, default: 13) – Signal line EMA period.

Returns:

tsi and signal.

Return type:

dict[str, Series]

awesome_oscillator(high, low, fast=5, slow=34)[source]

Awesome Oscillator (AO).

AO = SMA(median_price, fast) - SMA(median_price, slow)

Developed by Bill Williams. Measures market momentum using the difference between a 5-period and 34-period SMA of the midpoint price.

Interpretation:
  • Above zero: Bullish momentum (short-term average > long-term average).

  • Below zero: Bearish momentum.

  • Zero-line crossover: AO crossing above zero = buy signal; crossing below = sell signal.

  • Twin peaks (bullish): Two lows below zero where the second is higher than the first, followed by a green bar.

  • Twin peaks (bearish): Two highs above zero where the second is lower than the first, followed by a red bar.

  • Saucer: Three consecutive bars above zero where the middle bar is lowest = continuation buy signal.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • fast (int, default: 5) – Fast SMA period.

  • slow (int, default: 34) – Slow SMA period.

Returns:

AO values (unbounded, oscillates around zero).

Return type:

Series

ppo(data, fast=12, slow=26, signal=9)[source]

Percentage Price Oscillator (PPO).

Like MACD but expressed as a percentage of the slow EMA, making it comparable across different price levels and assets.

Interpretation:
  • Same signals as MACD: signal-line crossovers, zero-line crossovers, histogram analysis, and divergences.

  • Advantage over MACD: Because it is percentage-based, you can compare PPO values across stocks of different prices.

  • > 0: Fast EMA is above slow EMA = bullish.

  • < 0: Fast EMA is below slow EMA = bearish.

  • Histogram: Grows when momentum accelerates, shrinks when momentum decelerates.

Trading rules:
  • Same as MACD: buy on bullish signal crossover, sell on bearish signal crossover.

  • Use PPO instead of MACD when comparing momentum across multiple securities.

Parameters:
  • data (Series) – Price series.

  • fast (int, default: 12) – Fast EMA period.

  • slow (int, default: 26) – Slow EMA period.

  • signal (int, default: 9) – Signal EMA period.

Returns:

ppo, signal, histogram.

Return type:

dict[str, Series]

ultimate_oscillator(high, low, close, period1=7, period2=14, period3=28)[source]

Ultimate Oscillator.

Combines buying pressure across three timeframes (7, 14, 28 by default) into a single oscillator. Reduces false signals by incorporating multiple periods.

Interpretation:
  • > 70: Overbought.

  • < 30: Oversold.

  • Divergence: The primary signal. A bullish divergence occurs when price makes a new low but the UO does not, AND the UO is below 30. A bearish divergence occurs when price makes a new high but UO does not, AND UO is above 70.

Trading rules (Larry Williams’ method):
  • Buy on bullish divergence: price makes lower low, UO makes higher low, UO dips below 30, then UO breaks above the divergence high.

  • Sell when UO rises above 70, or when UO crosses below 50 after a buy signal.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period1 (int, default: 7) – First (shortest) period.

  • period2 (int, default: 14) – Second period.

  • period3 (int, default: 28) – Third (longest) period.

Returns:

Ultimate Oscillator values in [0, 100].

Return type:

Series

cmo(data, period=14)[source]

Chande Momentum Oscillator (CMO).

Similar to RSI but uses the difference between gains and losses divided by their sum, producing an oscillator in [-100, +100] instead of [0, 100].

Interpretation:
  • > +50: Strong bullish momentum, potentially overbought.

  • < -50: Strong bearish momentum, potentially oversold.

  • Zero crossover: CMO crossing above 0 = bullish; below = bearish.

  • Unlike RSI, CMO is symmetric around zero, making it easier to read directional bias.

Trading rules:
  • Buy when CMO crosses above -50 (leaving oversold).

  • Sell when CMO crosses below +50 (leaving overbought).

  • Use zero-line crossover as a trend filter.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Look-back period.

Returns:

CMO values in [-100, 100].

Return type:

Series

dpo(data, period=20)[source]

Detrended Price Oscillator (DPO).

DPO = close - SMA(close, period).shift(period // 2 + 1)

Removes the trend component from price to isolate cycles. Unlike most oscillators, DPO is not a momentum indicator – it helps identify cycle highs and lows.

Interpretation:
  • Positive: Price is above the displaced moving average (cycle high territory).

  • Negative: Price is below the displaced moving average (cycle low territory).

  • Peaks and troughs: Mark cycle turning points. Measure the time between peaks to estimate the dominant cycle length.

  • Not useful for trend trading; best for timing entries within a known cycle.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – SMA period. Should approximate the expected cycle length.

Returns:

DPO values (unbounded, oscillates around zero).

Return type:

Series

kst(data, roc1=10, roc2=15, roc3=20, roc4=30, sma1=10, sma2=10, sma3=10, sma4=15, signal_period=9)[source]

Know Sure Thing (KST) oscillator.

Weighted sum of four smoothed rate-of-change values with weights 1, 2, 3, 4. A comprehensive momentum indicator that combines multiple timeframes.

Interpretation:
  • KST above zero: Overall momentum is bullish across timeframes.

  • KST below zero: Overall momentum is bearish.

  • Signal line crossover: KST crossing above signal = buy; crossing below = sell.

  • Zero-line crossover: Confirms broader trend shifts.

  • Divergence: Price makes new high but KST does not = bearish divergence.

Trading rules:
  • Buy when KST crosses above its signal line, preferably when both are below zero (early trend entry).

  • Sell when KST crosses below its signal line.

Parameters:
  • data (Series) – Price series (typically close).

  • roc1 (int, default: 10) – First ROC period.

  • roc2 (int, default: 15) – Second ROC period.

  • roc3 (int, default: 20) – Third ROC period.

  • roc4 (int, default: 30) – Fourth ROC period.

  • sma1 (int, default: 10) – SMA smoothing for first ROC.

  • sma2 (int, default: 10) – SMA smoothing for second ROC.

  • sma3 (int, default: 10) – SMA smoothing for third ROC.

  • sma4 (int, default: 15) – SMA smoothing for fourth ROC.

  • signal_period (int, default: 9) – SMA period for the signal line.

Returns:

kst and signal.

Return type:

dict[str, Series]

Example

>>> result = kst(close)
>>> result["kst"]
connors_rsi(data, rsi_period=3, streak_period=2, rank_period=100)[source]

Connors RSI – composite of RSI, up/down streak RSI, and percentile rank.

ConnorsRSI = (RSI(close, rsi_period) + RSI(streak, streak_period) + PercentRank(pct_change, rank_period)) / 3

Designed specifically for mean-reversion trading. Combines three components to identify short-term overbought/oversold extremes.

Interpretation:
  • > 90: Extremely overbought – high probability of short-term pullback.

  • < 10: Extremely oversold – high probability of short-term bounce.

  • 70-90: Moderately overbought.

  • 10-30: Moderately oversold.

  • Best on liquid, large-cap stocks and ETFs; not reliable on low-volume or highly trending instruments.

Trading rules:
  • Buy when ConnorsRSI drops below 10 (mean reversion entry).

  • Sell when ConnorsRSI rises above 70 (exit for profit).

  • Use with a trend filter (e.g., above 200 SMA = only buy).

Parameters:
  • data (Series) – Price series (typically close).

  • rsi_period (int, default: 3) – Look-back for the standard RSI component.

  • streak_period (int, default: 2) – Look-back for the streak RSI component.

  • rank_period (int, default: 100) – Look-back for the percentile rank of the one-bar ROC.

Returns:

Connors RSI values in [0, 100].

Return type:

Series

Example

>>> result = connors_rsi(close)
fisher_transform(high, low, period=9)[source]

Fisher Transform – normalizes prices to a Gaussian distribution.

Uses the midpoint (high + low) / 2, normalizes to [-1, 1] over the look-back window, then applies the inverse hyperbolic tangent (Fisher Transform). Produces sharp, clear turning points.

Interpretation:
  • > +1.5: Extreme bullish – price may be overextended.

  • < -1.5: Extreme bearish – price may be oversold.

  • Signal line crossover: Fisher crossing above signal = bullish; crossing below = bearish.

  • Fisher Transform values have no upper/lower bound, but values beyond +/-2.5 are rare and signal extremes.

Trading rules:
  • Buy when Fisher crosses above its signal line in negative territory (reversal from oversold).

  • Sell when Fisher crosses below its signal line in positive territory (reversal from overbought).

  • The indicator is leading – it often turns before price.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 9) – Look-back period for normalization.

Returns:

fisher (current value) and signal (one-bar lag).

Return type:

dict[str, Series]

Example

>>> result = fisher_transform(high, low)
>>> result["fisher"]
elder_ray(high, low, close, period=13)[source]

Elder Ray Index – bull power and bear power.

bull_power = high - EMA(close, period) bear_power = low - EMA(close, period)

Measures the distance between the high/low and the EMA, showing how much power buyers (bulls) and sellers (bears) have.

Interpretation:
  • Bull power > 0: Bulls pushed price above EMA = buyers are in control.

  • Bear power < 0: Bears pushed price below EMA = sellers are in control (this is the normal state).

  • Bear power > 0: Extremely bullish – even the lows are above the EMA.

  • Bull power < 0: Extremely bearish – even the highs cannot reach the EMA.

  • Divergence: New price high with lower bull power = weakening.

Trading rules (Elder’s Triple Screen):
  • Buy when EMA is rising (trend filter) AND bear power is negative but rising (dip-buying).

  • Sell when EMA is falling AND bull power is positive but falling.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 13) – EMA period.

Returns:

bull_power and bear_power.

Return type:

dict[str, Series]

Example

>>> result = elder_ray(high, low, close)
>>> result["bull_power"]
aroon_oscillator(high, low, period=25)[source]

Aroon Oscillator – difference between Aroon Up and Aroon Down.

Aroon Up = 100 * (period - bars_since_high) / period Aroon Down = 100 * (period - bars_since_low) / period Aroon Oscillator = Aroon Up - Aroon Down

Measures the strength and direction of a trend by comparing how recently the highest high and lowest low occurred.

Interpretation:
  • Near +100: Strong uptrend (new highs are recent, new lows are distant).

  • Near -100: Strong downtrend (new lows are recent, new highs are distant).

  • Near 0: No clear trend (consolidation / range-bound).

  • Zero-line crossover: Oscillator crossing above 0 = new uptrend starting; crossing below = new downtrend.

Trading rules:
  • Buy when oscillator crosses above 0.

  • Sell when oscillator crosses below 0.

  • Strong signals when oscillator exceeds +50 or drops below -50.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 25) – Look-back period.

Returns:

Aroon Oscillator values in [-100, 100].

Return type:

Series

Example

>>> result = aroon_oscillator(high, low, period=25)
chande_forecast_oscillator(data, period=14)[source]

Chande Forecast Oscillator (CFO).

Percentage difference between the close and the period-bar linear regression forecast value.

CFO = ((close - linreg_forecast) / close) * 100

Interpretation:
  • Positive: Price is above the regression forecast – bullish deviation from trend.

  • Negative: Price is below the regression forecast – bearish deviation.

  • Zero-line crossover: Shift from bearish to bullish (or vice versa) relative to the regression trend.

  • Persistent positive values indicate an uptrend; persistent negative values indicate a downtrend.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – Linear regression look-back period.

Returns:

CFO values (percentage, unbounded).

Return type:

Series

Example

>>> result = chande_forecast_oscillator(close, period=14)
balance_of_power(open_, high, low, close, period=14)[source]

Balance of Power (BOP).

BOP = SMA((close - open) / (high - low), period)

Measures the strength of buyers vs sellers by comparing the close-open range to the high-low range.

Interpretation:
  • Positive: Buyers dominated (close > open relative to range).

  • Negative: Sellers dominated (close < open relative to range).

  • Near +1: Extreme buying pressure.

  • Near -1: Extreme selling pressure.

  • Zero-line crossover: Shift in control from buyers to sellers or vice versa.

  • Divergence: Price makes new high but BOP is declining = distribution (smart money selling).

Trading rules:
  • Buy when BOP crosses above zero.

  • Sell when BOP crosses below zero.

  • Divergence with price is a strong reversal signal.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – SMA smoothing period.

  • open_ (Series)

Returns:

BOP values in [-1, 1] (when smoothed, may slightly exceed bounds).

Return type:

Series

Example

>>> result = balance_of_power(open_, high, low, close)
Parameters:
Return type:

Series

qstick(open_, close, period=14)[source]

QStick indicator – moving average of (close - open).

Quantifies the dominance of bullish vs bearish candlesticks over the look-back period.

Interpretation:
  • Positive: On average, candles are closing above their open (more bullish bars) = buying pressure.

  • Negative: On average, candles are closing below their open (more bearish bars) = selling pressure.

  • Zero-line crossover: Shift from bearish to bullish bars or vice versa.

  • Magnitude: Larger values = stronger candlestick conviction.

Parameters:
  • open (pd.Series) – Open prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – SMA period.

  • open_ (Series)

Returns:

QStick values.

Return type:

Series

Example

>>> result = qstick(open_, close, period=14)
Parameters:
Return type:

Series

coppock_curve(data, wma_period=10, long_roc=14, short_roc=11)[source]

Coppock Curve – weighted moving average of the sum of two ROCs.

Coppock = WMA(ROC(long_roc) + ROC(short_roc), wma_period)

Originally designed for monthly charts to identify long-term buying opportunities in the S&P 500. One of the few indicators specifically designed to detect major market bottoms.

Interpretation:
  • Zero-line crossover from below: The primary buy signal. Indicates the market is turning up from a major bottom.

  • Above zero and rising: Bullish momentum confirmed.

  • Below zero: Market is in or recovering from a downturn.

  • Traditionally, only buy signals are used (zero crossover from below). Sell signals are less reliable.

Trading rules:
  • Buy when the Coppock Curve crosses above zero.

  • This is a long-term indicator; best on monthly data for identifying multi-year buying opportunities.

Parameters:
  • data (Series) – Price series (typically close).

  • wma_period (int, default: 10) – Weighted moving average period.

  • long_roc (int, default: 14) – Long rate-of-change period.

  • short_roc (int, default: 11) – Short rate-of-change period.

Returns:

Coppock Curve values (unbounded).

Return type:

Series

Example

>>> result = coppock_curve(close)
relative_vigor_index(open_, high, low, close, period=10)[source]

Relative Vigor Index (RVI).

Measures the conviction of a recent price move by comparing the close-open range to the high-low range, smoothed with a symmetric-weighted moving average and then a simple moving average.

The idea is that in bull markets, prices tend to close near their highs (high vigor), and in bear markets near their lows.

Interpretation:
  • Above zero: Closing prices tend to be above opening prices = bullish energy.

  • Below zero: Closing prices tend to be below opening prices = bearish energy.

  • Signal line crossover: RVI crossing above signal = buy; crossing below = sell.

  • Divergence: Price makes new high but RVI does not = conviction is weakening.

Trading rules:
  • Buy when RVI crosses above its signal line.

  • Sell when RVI crosses below its signal line.

  • Best combined with a trend indicator for confirmation.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 10) – SMA smoothing period.

  • open_ (Series)

Returns:

rvi and signal.

Return type:

dict[str, Series]

Example

>>> result = relative_vigor_index(open_, high, low, close)
>>> result["rvi"]
Parameters:
Return type:

dict[str, Series]

schaff_momentum(data, period=10, fast=23, slow=50)[source]

Schaff Trend Cycle applied to momentum (Schaff Momentum).

Applies two rounds of Stochastic smoothing to the difference between fast and slow EMAs, producing a bounded oscillator in [0, 100].

Interpretation:
  • > 75: Bullish – trend cycle is in the upper zone.

  • < 25: Bearish – trend cycle is in the lower zone.

  • 25-75: Transition zone.

  • Crosses above 25: Buy signal (turning bullish).

  • Crosses below 75: Sell signal (turning bearish).

  • Faster than MACD because of the double stochastic smoothing; provides earlier signals but may also have more false signals.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 10) – Stochastic look-back period.

  • fast (int, default: 23) – Fast EMA period.

  • slow (int, default: 50) – Slow EMA period.

Returns:

Schaff Momentum values in [0, 100].

Return type:

Series

Example

>>> result = schaff_momentum(close, period=10)
price_momentum_oscillator(data, short=35, long=20, signal=10)[source]

Price Momentum Oscillator (PMO) – double-smoothed ROC.

PMO = EMA(EMA(ROC(1), short), long)

Developed by Carl Swenlin, the PMO is a double-smoothed one-bar rate-of-change, scaled by a factor of 10 for visibility.

Interpretation:
  • Above zero: Bullish momentum (price trend is up).

  • Below zero: Bearish momentum.

  • Signal line crossover: PMO crossing above signal = buy; crossing below = sell.

  • Zero-line crossover: Confirms a trend change.

  • Extreme readings: PMO values at historical extremes (relative to asset) indicate overextended moves.

  • Divergence: Price makes new high but PMO does not = bearish divergence.

Trading rules:
  • Buy on bullish signal-line crossover, especially near zero or in negative territory.

  • Sell on bearish signal-line crossover.

Parameters:
  • data (Series) – Price series (typically close).

  • short (int, default: 35) – First smoothing EMA period.

  • long (int, default: 20) – Second smoothing EMA period.

  • signal (int, default: 10) – Signal line EMA period.

Returns:

pmo and signal.

Return type:

dict[str, Series]

Example

>>> result = price_momentum_oscillator(close)
>>> result["pmo"]
klinger_oscillator(high, low, close, volume, fast=34, slow=55, signal=13)[source]

Klinger Volume Oscillator – momentum-oriented view.

Uses the relationship between price trend direction and volume to predict price reversals. Combines volume with trend to identify accumulation and distribution.

Interpretation:
  • KVO above zero: Volume flow is bullish (accumulation).

  • KVO below zero: Volume flow is bearish (distribution).

  • Signal line crossover: KVO crossing above signal = buy; crossing below = sell.

  • Divergence: Price makes new high but KVO does not = distribution occurring despite rising prices.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • fast (int, default: 34) – Fast EMA period.

  • slow (int, default: 55) – Slow EMA period.

  • signal (int, default: 13) – Signal line EMA period.

Returns:

kvo and signal.

Return type:

dict[str, Series]

Example

>>> result = klinger_oscillator(high, low, close, volume)
>>> result["kvo"]
stochastic_momentum_index(high, low, close, period=14, smooth_k=3, smooth_d=3)[source]

Stochastic Momentum Index (SMI).

The SMI is a refinement of the Stochastic Oscillator that measures the distance of the close relative to the midpoint of the high-low range, double-smoothed with EMAs.

Interpretation:
  • > +40: Overbought zone.

  • < -40: Oversold zone.

  • Zero-line crossover: SMI above 0 = bullish; below = bearish.

  • Signal line crossover: SMI crossing above signal = buy; crossing below = sell.

  • More refined than Stochastic because it measures distance from the midpoint rather than from the low, reducing noise.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

  • smooth_k (int, default: 3) – First smoothing EMA period.

  • smooth_d (int, default: 3) – Signal line EMA period.

Returns:

smi and signal.

Return type:

dict[str, Series]

Example

>>> result = stochastic_momentum_index(high, low, close)
>>> result["smi"]
inertia(close, high, low, rvi_period=10, linreg_period=20)[source]

Ehlers Inertia Indicator – RVI smoothed by linear regression.

Applies a linear regression (moving regression value) to the Relative Volatility Index (RVI) to produce a momentum-like indicator.

Interpretation:
  • Above 50: Bullish – volatility conditions favor upside.

  • Below 50: Bearish – volatility conditions favor downside.

  • 50 crossover: Trend direction change signal.

  • Smoother than raw RVI due to the regression smoothing, so it gives clearer trend signals with fewer whipsaws.

Parameters:
  • close (Series) – Close prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • rvi_period (int, default: 10) – Period for computing the RVI.

  • linreg_period (int, default: 20) – Linear regression look-back period.

Returns:

Inertia values. Values above 50 are bullish; below 50 are bearish.

Return type:

Series

Example

>>> result = inertia(close, high, low)
squeeze_histogram(high, low, close, period=20, linreg_period=20)[source]

Squeeze Histogram – momentum component of the TTM Squeeze.

Computes the linear regression value of close - midline where midline is the average of the highest high and lowest low over the period, combined with the SMA.

Interpretation:
  • Positive and growing: Bullish momentum accelerating.

  • Positive and shrinking: Bullish momentum decelerating (potential top forming).

  • Negative and growing (more negative): Bearish momentum accelerating.

  • Negative and shrinking: Bearish momentum decelerating (potential bottom forming).

  • Color changes (when plotted): Dark green = accelerating bullish, light green = decelerating bullish, dark red = accelerating bearish, light red = decelerating bearish.

Trading rules:
  • Use with squeeze detection (BB inside KC). When squeeze fires (BB exits KC), trade in the direction of the histogram.

  • Buy when histogram turns positive after a squeeze release.

  • Sell when histogram turns negative after a squeeze release.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – Donchian / Bollinger look-back period.

  • linreg_period (int, default: 20) – Linear regression period for the momentum value.

Returns:

Squeeze momentum histogram values.

Return type:

Series

Example

>>> result = squeeze_histogram(high, low, close)
center_of_gravity(data, period=10)[source]

Ehlers Center of Gravity Oscillator.

A weighted sum of recent prices where more recent bars receive higher weight, normalized by a simple sum. This produces a leading oscillator.

Interpretation:
  • Oscillates around a negative value: The center of gravity shifts based on where price weight is concentrated.

  • Peaks and troughs: Mark potential turning points with virtually zero lag.

  • Leading indicator: Turns before price does, making it useful for timing entries.

  • Best used for cycle-based trading on short timeframes.

CoG = -sum(price[i] * (i+1), i=0..period-1) / sum(price[i], i=0..period-1)

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 10) – Look-back period.

Returns:

Center of Gravity values (oscillates around zero).

Return type:

Series

Example

>>> result = center_of_gravity(close, period=10)
psychological_line(data, period=12)[source]

Psychological Line — percentage of up days over N periods.

PSY = (number of up bars in period) / period * 100

Values above 50 suggest bullish sentiment; below 50 suggest bearish.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 12) – Look-back period.

Returns:

Psychological Line values in [0, 100].

Return type:

Series

Example

>>> result = psychological_line(close, period=12)

Volume Indicators

Volume-confirmed signals and accumulation/distribution studies.

Volume-based indicators.

This module provides indicators that incorporate volume data to measure buying/selling pressure and trend confirmation. All functions accept pd.Series inputs and return pd.Series.

obv(close, volume)[source]

On Balance Volume (OBV).

OBV is a cumulative running total of volume. Volume is added on up-close days and subtracted on down-close days.

Interpretation:
  • Rising OBV: Volume is flowing in (accumulation) – bullish.

  • Falling OBV: Volume is flowing out (distribution) – bearish.

  • Divergence: The most important signal. Price makes a new high but OBV does not = smart money is not confirming the move (bearish divergence). Price makes a new low but OBV does not = accumulation is occurring (bullish divergence).

  • Breakout confirmation: OBV breaking to a new high alongside price confirms the breakout is genuine.

Trading rules:
  • Buy when OBV diverges bullishly from price (price falls, OBV holds or rises).

  • Sell when OBV diverges bearishly from price (price rises, OBV flattens or falls).

  • Use OBV trend (rising/falling) to confirm price trends.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

OBV values.

Return type:

Series

vwap(high, low, close, volume)[source]

Volume Weighted Average Price (VWAP).

Computed as the cumulative sum of typical_price * volume divided by cumulative volume. This is the intraday running VWAP; for session-reset VWAP, pre-group your data by session.

Interpretation:
  • Price above VWAP: Buyers are in control; longs entered at good prices relative to the average fill.

  • Price below VWAP: Sellers are in control.

  • VWAP as support/resistance: Institutional traders use VWAP as a benchmark. Price tends to gravitate toward VWAP.

  • Mean reversion: Extreme deviations from VWAP tend to revert, especially intraday.

Trading rules:
  • Buy pullbacks to VWAP in an uptrend (institutional support).

  • Sell rallies to VWAP in a downtrend (institutional resistance).

  • Institutions aim to buy below VWAP and sell above it; track whether your fills are better than VWAP.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

Cumulative VWAP values.

Return type:

Series

ad_line(high, low, close, volume)[source]

Accumulation/Distribution Line (AD Line).

Uses the Close Location Value (CLV) money flow multiplier.

Interpretation:
  • Rising AD line: Accumulation – buying pressure dominates. Volume is flowing into the asset.

  • Falling AD line: Distribution – selling pressure dominates.

  • Divergence: Price makes new high but AD does not = distribution despite rising prices (bearish). Price makes new low but AD does not = accumulation (bullish).

  • Unlike OBV, the AD line considers where the close is within the high-low range, not just the direction of the close.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

Cumulative A/D line values.

Return type:

Series

cmf(high, low, close, volume, period=20)[source]

Chaikin Money Flow (CMF).

Measures money flow volume over a rolling period, showing whether buying or selling pressure is dominant.

Interpretation:
  • Positive (> 0): Buying pressure (accumulation). The higher the value, the stronger the buying.

  • Negative (< 0): Selling pressure (distribution).

  • > +0.25: Strong buying pressure.

  • < -0.25: Strong selling pressure.

  • Zero-line crossover: Shift from accumulation to distribution or vice versa.

  • Divergence: Price makes new high but CMF is falling = distribution.

Trading rules:
  • Buy when CMF crosses above zero (accumulation starting).

  • Sell when CMF crosses below zero (distribution starting).

  • Confirm breakouts: price breaking resistance with positive CMF is more reliable.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 20) – Look-back period.

Returns:

CMF values in [-1, 1].

Return type:

Series

mfi(high, low, close, volume, period=14)[source]

Money Flow Index (MFI).

Often called the volume-weighted RSI. Incorporates both price and volume to identify overbought/oversold conditions.

Interpretation:
  • > 80: Overbought – high buying pressure, potential reversal.

  • < 20: Oversold – high selling pressure, potential bounce.

  • Divergence: Price makes new high but MFI does not = weakening volume-confirmed momentum (bearish).

  • More reliable than RSI alone because it includes volume: a price move on heavy volume is more meaningful.

Trading rules:
  • Buy when MFI crosses above 20 (leaving oversold).

  • Sell when MFI crosses below 80 (leaving overbought).

  • MFI divergence with price is a strong reversal signal.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 14) – Look-back period.

Returns:

MFI values in [0, 100].

Return type:

Series

eom(high, low, volume, period=14)[source]

Ease of Movement (EMV / EOM).

Relates price change to volume, showing how easily price is moving.

Interpretation:
  • Positive: Price is advancing on relatively low volume (easy movement up) = bullish.

  • Negative: Price is declining on relatively low volume (easy movement down) = bearish.

  • Near zero: Price movement requires substantial volume = indecision or strong resistance/support.

  • Zero-line crossover: Shift from easy upward to easy downward movement or vice versa.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • volume (Series) – Volume data.

  • period (int, default: 14) – Smoothing period.

Returns:

EOM values (smoothed).

Return type:

Series

force_index(close, volume, period=13)[source]

Force Index.

Force = close.diff() * volume, then smoothed with EMA.

Combines price change and volume to measure the strength behind a move.

Interpretation:
  • Positive: Buying force – price is rising with volume.

  • Negative: Selling force – price is falling with volume.

  • Magnitude: Larger values = stronger force behind the move.

  • Zero-line crossover: Shift from buying to selling force.

  • Divergence: Price makes new high but Force Index is declining = momentum weakening.

Trading rules:
  • Buy when Force Index crosses above zero in an uptrend (pullback entry).

  • Sell when Force Index crosses below zero in a downtrend.

  • Use short period (2) for entries, longer period (13) for trend confirmation.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 13) – EMA smoothing period.

Returns:

Smoothed Force Index.

Return type:

Series

nvi(close, volume)[source]

Negative Volume Index (NVI).

NVI focuses on days when volume decreases; the assumption is that smart money is active on low-volume days.

Interpretation:
  • Rising NVI: Smart money is buying on quiet days.

  • Falling NVI: Smart money is selling on quiet days.

  • NVI above its 255-day MA: Bull market (historically correct ~96% of the time according to Norman Fosback).

  • NVI below its 255-day MA: Bear market.

  • Compare with PVI to distinguish smart vs. crowd behavior.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

NVI values (starts at 1000).

Return type:

Series

pvi(close, volume)[source]

Positive Volume Index (PVI).

PVI focuses on days when volume increases; the assumption is that the crowd follows price on high-volume days.

Interpretation:
  • Rising PVI: The crowd is buying on high-volume days.

  • Falling PVI: The crowd is selling on high-volume days.

  • PVI below its 255-day MA: Bearish sign (the crowd is pushing prices down on active days).

  • PVI tends to track what the public/retail traders are doing; NVI tracks institutional/smart money behavior.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

PVI values (starts at 1000).

Return type:

Series

vpt(close, volume)[source]

Volume Price Trend (VPT).

VPT = cumsum(volume * pct_change(close))

Interpretation:
  • Rising VPT: Volume is confirming the price trend (bullish).

  • Falling VPT: Volume is working against the price trend.

  • Divergence: Price rises but VPT falls = distribution.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

VPT values.

Return type:

Series

adosc(high, low, close, volume, fast=3, slow=10)[source]

Accumulation/Distribution Oscillator (Chaikin Oscillator).

ADOSC = EMA(AD, fast) - EMA(AD, slow)

Interpretation:
  • Positive: Short-term accumulation exceeds long-term = money is flowing in.

  • Negative: Short-term distribution exceeds long-term = money is flowing out.

  • Zero-line crossover: Buy when crossing above zero, sell when crossing below.

  • Divergence: Price makes new high but oscillator falls = distribution.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • fast (int, default: 3) – Fast EMA period.

  • slow (int, default: 10) – Slow EMA period.

Returns:

Chaikin Oscillator values.

Return type:

Series

vwma(close, volume, period=20)[source]

Volume Weighted Moving Average (VWMA).

A simple moving average weighted by volume. When volume is uniform this reduces to the standard SMA.

VWMA = SUM(close * volume, period) / SUM(volume, period)

Interpretation:
  • Price above VWMA: Bullish – volume-confirmed uptrend.

  • Price below VWMA: Bearish – volume-confirmed downtrend.

  • VWMA vs SMA: When VWMA > SMA, heavy volume is occurring at higher prices (accumulation). When VWMA < SMA, heavy volume is at lower prices (distribution).

  • More responsive to volume spikes than a standard SMA.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 20) – Look-back period.

Returns:

VWMA values.

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 13, 14.0])
>>> volume = pd.Series([100, 100, 100, 100, 100.0])
>>> vwma(close, volume, period=3)  # equals SMA when volume is uniform
pvt(close, volume)[source]

Price Volume Trend (PVT).

A cumulative indicator that adds a portion of volume proportional to the percentage change in close price.

PVT = cumsum(pct_change(close) * volume)

This is functionally equivalent to vpt() but is provided as the commonly-used PVT alias.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

PVT values.

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12.0])
>>> volume = pd.Series([100, 200, 300.0])
>>> pvt(close, volume)
vpt_smoothed(close, volume, period=14)[source]

Volume Price Trend with EMA smoothing.

Applies an EMA to the raw VPT line to reduce noise.

VPT_SMOOTHED = EMA(cumsum(pct_change(close) * volume), period)

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 14) – EMA smoothing period.

Returns:

Smoothed VPT values.

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 13, 14.0])
>>> volume = pd.Series([100, 200, 300, 400, 500.0])
>>> vpt_smoothed(close, volume, period=3)
klinger(high, low, close, volume, fast=34, slow=55, signal=13)[source]

Klinger Volume Oscillator (KVO).

Uses the relationship between price trend direction and volume to predict price reversals.

Interpretation:
  • KVO above zero: Net volume flow is bullish (accumulation).

  • KVO below zero: Net volume flow is bearish (distribution).

  • Signal line crossover: KVO crossing above signal = buy; crossing below = sell.

  • Divergence: Price at new high but KVO declining = money flowing out despite rising prices (distribution).

Trading rules:
  • Buy when KVO crosses above its signal line.

  • Sell when KVO crosses below its signal line.

  • Best for confirming price breakouts with volume support.

trend = sign(hlc3 - hlc3.shift(1)) dm = high - low cm = cumulative dm when trend unchanged, else dm vf = volume * abs(2 * dm / cm - 1) * trend * 100 KVO = EMA(vf, fast) - EMA(vf, slow) signal_line = EMA(KVO, signal)

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • fast (int, default: 34) – Fast EMA period.

  • slow (int, default: 55) – Slow EMA period.

  • signal (int, default: 13) – Signal line EMA period.

Returns:

{"kvo": <pd.Series>, "signal": <pd.Series>}

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(0)
>>> n = 100
>>> close = pd.Series(100 + np.cumsum(np.random.randn(n) * 0.5))
>>> high = close + 0.5
>>> low = close - 0.5
>>> volume = pd.Series(np.random.randint(1000, 5000, n).astype(float))
>>> result = klinger(high, low, close, volume)
>>> result["kvo"].name
'kvo'
taker_buy_ratio(buy_volume, total_volume)[source]

Taker Buy Ratio.

A helper for exchange-level data that computes the fraction of volume coming from taker buys.

ratio = buy_volume / total_volume

Values above 0.5 indicate net buying pressure; below 0.5 indicate net selling pressure.

Parameters:
  • buy_volume (Series) – Taker buy volume.

  • total_volume (Series) – Total volume.

Returns:

Ratio in [0, 1] (NaN where total_volume is 0).

Return type:

Series

Example

>>> import pandas as pd
>>> buy = pd.Series([50, 60, 40.0])
>>> total = pd.Series([100, 100, 100.0])
>>> taker_buy_ratio(buy, total)
elder_force(close, volume, period=2)[source]

Elder’s Force Index (EMA-smoothed variant).

This is Elder’s original formulation using a short EMA (default 2). For a longer-term variant, increase period.

Interpretation:
  • Positive: Buying force (price rising with volume).

  • Negative: Selling force (price falling with volume).

  • 2-period: Use for short-term entry timing within a trend. Buy dips to zero or slightly negative in an uptrend.

  • 13-period: Use for trend direction confirmation.

  • Divergence: Price new high but Force declining = weakening.

raw = close.diff() * volume elder_force = EMA(raw, period)

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • period (int, default: 2) – EMA smoothing period.

Returns:

Smoothed Elder Force Index.

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 13.0])
>>> volume = pd.Series([100, 200, 150, 300, 250.0])
>>> elder_force(close, volume, period=2)
volume_profile(close, volume, bins=10)[source]

Volume Profile (volume at price).

Distributes volume into bins equally-spaced price buckets. This is useful for identifying high-volume nodes (support/resistance) and low-volume nodes (price gaps).

Interpretation:
  • High-volume nodes (HVN): Price levels where significant trading occurred = strong support/resistance. Price tends to consolidate at these levels.

  • Low-volume nodes (LVN): Price levels with little trading = price tends to move quickly through these zones.

  • Point of control (POC): The price level with the highest volume = strongest S/R level.

  • Value area: The range containing ~70% of volume = fair value zone.

Parameters:
  • close (Series) – Close prices (used to assign volume to price levels).

  • volume (Series) – Volume data.

  • bins (int, default: 10) – Number of price bins.

Returns:

{"price_bins": <pd.Series of bin labels>, "volume": <pd.Series of aggregated volume>}

Return type:

dict[str, Series]

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10.0])
>>> volume = pd.Series([100, 200, 300, 200, 100.0])
>>> vp = volume_profile(close, volume, bins=3)
>>> len(vp["volume"])
3
accumulation_distribution_oscillator(high, low, close, volume, fast=3, slow=10)[source]

Accumulation/Distribution Oscillator.

Computes the difference between a fast and slow EMA of the Accumulation/Distribution line. This is equivalent to the Chaikin Oscillator (adosc()) but provided under its full descriptive name.

AD_OSC = EMA(AD, fast) - EMA(AD, slow)

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • volume (Series) – Volume data.

  • fast (int, default: 3) – Fast EMA period.

  • slow (int, default: 10) – Slow EMA period.

Returns:

Oscillator values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(0)
>>> n = 50
>>> close = pd.Series(100 + np.cumsum(np.random.randn(n) * 0.5))
>>> high = close + 0.5
>>> low = close - 0.5
>>> volume = pd.Series(np.random.randint(1000, 5000, n).astype(float))
>>> accumulation_distribution_oscillator(high, low, close, volume)
volume_roc(volume, period=14)[source]

Volume Rate of Change (Volume ROC).

Measures the percentage change in volume over a given period.

Interpretation:
  • Large positive: Volume is surging compared to period bars ago = heightened interest, possible breakout.

  • Large negative: Volume is drying up = decreasing interest.

  • Volume spike with price breakout: Confirms the breakout.

  • Volume spike without price movement: Potential distribution or accumulation before a move.

volume_roc = (volume - volume.shift(period)) / volume.shift(period) * 100

Parameters:
  • volume (Series) – Volume data.

  • period (int, default: 14) – Look-back period.

Returns:

Volume ROC as a percentage.

Return type:

Series

Example

>>> import pandas as pd
>>> volume = pd.Series([100, 120, 110, 130, 140.0])
>>> volume_roc(volume, period=2)
positive_volume_index(close, volume)[source]

Positive Volume Index (PVI).

A descriptive-name alias for pvi(). PVI focuses on days when volume increases relative to the prior day.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

PVI values (starts at 1000).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 10, 12, 11.0])
>>> volume = pd.Series([100, 200, 150, 300, 100.0])
>>> positive_volume_index(close, volume).iloc[0]
1000.0

Trend Indicators

Trend direction, strength, and adaptive moving averages.

Trend indicators.

This module provides indicators that identify and measure the direction and strength of price trends. All functions accept pd.Series inputs and return pd.Series (or dict[str, pd.Series] for multi-output indicators).

adx(high, low, close, period=14)[source]

Average Directional Index (ADX) with +DI and -DI.

Measures the strength of a trend regardless of its direction. +DI and -DI show the direction.

Interpretation:
  • ADX > 25: Trend is strong enough to trade.

  • ADX > 50: Very strong trend.

  • ADX < 20: No trend (range-bound / choppy).

  • ADX rising: Trend is strengthening.

  • ADX falling: Trend is weakening (not necessarily reversing).

  • +DI > -DI: Uptrend (buyers dominate).

  • -DI > +DI: Downtrend (sellers dominate).

  • +DI/-DI crossover: Trend direction change.

Trading rules:
  • Buy when +DI crosses above -DI AND ADX > 25 (trending up).

  • Sell when -DI crosses above +DI AND ADX > 25 (trending down).

  • Avoid trading when ADX < 20 (no trend).

  • Use ADX as a filter: only apply trend-following strategies when ADX > 25; use mean-reversion when ADX < 20.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Smoothing period.

Returns:

adx, plus_di, minus_di — all in [0, 100].

Return type:

dict[str, Series]

aroon(high, low, period=25)[source]

Aroon Indicator.

Measures the time since the last high/low to identify trend direction and strength.

Interpretation:
  • Aroon Up > 70: Strong uptrend (recent new highs).

  • Aroon Down > 70: Strong downtrend (recent new lows).

  • Aroon Up < 30: Weak uptrend (no recent new highs).

  • Aroon Down < 30: Weak downtrend (no recent new lows).

  • Aroon Up crosses above Aroon Down: New uptrend starting.

  • Aroon Down crosses above Aroon Up: New downtrend starting.

  • Both below 50: Consolidation / no trend.

  • Oscillator: Positive = uptrend, negative = downtrend.

Trading rules:
  • Buy when Aroon Up crosses above Aroon Down.

  • Sell when Aroon Down crosses above Aroon Up.

  • Strongest signal when one Aroon is above 70 and the other is below 30.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 25) – Look-back period.

Returns:

aroon_up, aroon_down, oscillator — up/down in [0, 100], oscillator in [-100, 100].

Return type:

dict[str, Series]

psar(high, low, close, af_start=0.02, af_step=0.02, af_max=0.2)[source]

Parabolic SAR (Stop and Reverse).

A trend-following indicator that provides entry/exit points and trailing stop levels.

Interpretation:
  • SAR dots below price: Uptrend. The SAR value is a trailing stop / support level.

  • SAR dots above price: Downtrend. The SAR value is a trailing stop / resistance level.

  • SAR flip (below to above): Sell signal – trend has reversed from bullish to bearish.

  • SAR flip (above to below): Buy signal – trend has reversed from bearish to bullish.

Trading rules:
  • Buy when SAR flips below price (dots move under candles).

  • Sell when SAR flips above price (dots move above candles).

  • Use SAR values as trailing stop-loss levels.

  • Works best in trending markets; generates many false signals in ranging markets. Combine with ADX to filter.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • af_start (float, default: 0.02) – Initial acceleration factor.

  • af_step (float, default: 0.02) – Acceleration factor increment.

  • af_max (float, default: 0.2) – Maximum acceleration factor.

Returns:

Parabolic SAR values. Values above price indicate downtrend; values below price indicate uptrend.

Return type:

Series

vortex(high, low, close, period=14)[source]

Vortex Indicator.

Captures positive and negative trend movement by comparing the distance between current high/low and previous low/high.

Interpretation:
  • +VI > -VI: Uptrend – positive vortex movement dominates.

  • -VI > +VI: Downtrend – negative vortex movement dominates.

  • +VI crosses above -VI: Bullish trend change signal.

  • -VI crosses above +VI: Bearish trend change signal.

  • Both near 1.0: Trend is neutral or transitioning.

Trading rules:
  • Buy when +VI crosses above -VI.

  • Sell when -VI crosses above +VI.

  • Use a threshold (e.g. 1.1) to filter weak crossovers.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

Returns:

plus_vi and minus_vi.

Return type:

dict[str, Series]

trix(data, period=15)[source]

TRIX – Triple-smoothed EMA rate of change.

TRIX = 100 * ROC(EMA(EMA(EMA(data))))

Filters out insignificant price movements by triple-smoothing before computing the rate of change.

Interpretation:
  • Above zero: Bullish momentum (triple-smoothed trend up).

  • Below zero: Bearish momentum.

  • Zero-line crossover: Buy signal when crossing above zero; sell when crossing below.

  • Signal line: Often paired with a signal EMA for crossover signals.

  • Extremely smooth; good for identifying major trend changes but lags significantly.

Trading rules:
  • Buy when TRIX crosses above zero.

  • Sell when TRIX crosses below zero.

  • Use for long-term trend identification, not short-term timing.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 15) – EMA period for each smoothing pass.

Returns:

TRIX values.

Return type:

Series

linear_regression(data, period=14)[source]

Rolling Linear Regression.

Fits an OLS regression line to the last period values at each bar.

Interpretation:
  • Positive slope: Price trend is up over the window.

  • Negative slope: Price trend is down.

  • R-squared near 1: Price is moving in a clean line (strong trend with low noise).

  • R-squared near 0: No linear trend (choppy/range-bound).

  • Value: The regression endpoint acts as a smoothed trend line with less lag than a moving average.

Trading rules:
  • Trade in the direction of the slope when R-squared > 0.5.

  • Avoid trend-following trades when R-squared < 0.2.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Look-back window.

Returns:

value (end-of-line prediction), slope, intercept, r_squared.

Return type:

dict[str, Series]

linear_regression_slope(data, period=14)[source]

Rolling Linear Regression Slope.

A convenience wrapper around linear_regression() that returns only the slope component.

Interpretation:
  • Positive: Uptrend over the look-back period.

  • Negative: Downtrend.

  • Magnitude: Steeper slope = stronger trend.

  • Zero crossover: Trend direction change.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Look-back window.

Returns:

Slope values.

Return type:

Series

zigzag(close, pct_change=5.0)[source]

ZigZag indicator – connects swing highs and lows.

Identifies pivots where price reverses by at least pct_change percent, then linearly interpolates between them.

Interpretation:
  • Filters out noise to reveal the true swing structure of price.

  • Not a trading signal: The last segment repaints as new data arrives. Use only for historical analysis.

  • Swing counting: Measure the distance between pivots for wave analysis (Elliott Wave, harmonic patterns).

  • Support/resistance: Pivot levels often act as future S/R.

  • Useful for backtesting swing-trading strategies.

Parameters:
  • close (Series) – Close prices.

  • pct_change (float, default: 5.0) – Minimum percentage change to register a new pivot.

Returns:

ZigZag line (interpolated between pivots). Non-pivot bars are filled via linear interpolation; leading/trailing NaNs remain where no pivot has been established.

Return type:

Series

Example

>>> import pandas as pd
>>> zz = zigzag(pd.Series([100, 110, 105, 95, 100, 90]), pct_change=5.0)
heikin_ashi(open_, high, low, close)[source]

Heikin-Ashi modified OHLC candles.

Modified candlesticks that smooth price action and make trends easier to identify.

Interpretation:
  • Green HA candles with no lower shadow: Strong uptrend.

  • Red HA candles with no upper shadow: Strong downtrend.

  • Small body with long shadows: Indecision / potential reversal.

  • Color change: Possible trend reversal (green to red or vice versa).

  • HA candles smooth noise, making it easier to stay in trends and avoid premature exits.

Trading rules:
  • Stay long as long as HA candles remain green.

  • Stay short as long as HA candles remain red.

  • Watch for doji-like HA candles as reversal warnings.

  • Note: HA prices are synthetic – do not use them for actual order placement. Use regular prices for entries/exits.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

ha_open, ha_high, ha_low, ha_close.

Return type:

dict[str, Series]

Example

>>> import pandas as pd
>>> ha = heikin_ashi(
...     pd.Series([100, 102]),
...     pd.Series([105, 106]),
...     pd.Series([99, 101]),
...     pd.Series([104, 103]),
... )
Parameters:
Return type:

dict[str, Series]

mcginley_dynamic(data, period=14)[source]

McGinley Dynamic – adaptive moving average.

Adjusts its speed based on market velocity, reducing whipsaws compared to a standard EMA.

Interpretation:
  • Price above McGinley: Bullish trend.

  • Price below McGinley: Bearish trend.

  • Automatically speeds up in fast markets and slows down in slow markets, reducing false crossovers.

  • Acts as a more reliable dynamic support/resistance than traditional moving averages.

MD_t = MD_{t-1} + (price - MD_{t-1}) / (N * (price / MD_{t-1})^4)

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – Smoothing period.

Returns:

McGinley Dynamic values.

Return type:

Series

Example

>>> import pandas as pd
>>> md = mcginley_dynamic(pd.Series([100, 102, 101, 103, 105]))
schaff_trend_cycle(close, period=10, fast=23, slow=50)[source]

Schaff Trend Cycle – MACD passed through a double stochastic.

Combines the MACD histogram with stochastic smoothing for a faster, smoother oscillator bounded between 0 and 100.

Interpretation:
  • > 75: Bullish trend established.

  • < 25: Bearish trend established.

  • Crosses above 25: Buy signal (bearish-to-bullish shift).

  • Crosses below 75: Sell signal (bullish-to-bearish shift).

  • Faster than MACD because of the double stochastic processing.

  • Spends most of its time at extremes (near 0 or 100), with quick transitions between them.

Parameters:
  • close (Series) – Close prices.

  • period (int, default: 10) – Stochastic look-back period.

  • fast (int, default: 23) – Fast EMA period for MACD.

  • slow (int, default: 50) – Slow EMA period for MACD.

Returns:

STC values in [0, 100].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> stc = schaff_trend_cycle(pd.Series(np.random.randn(100).cumsum() + 100))
guppy_mma(data)[source]

Guppy Multiple Moving Average (GMMA).

Developed by Daryl Guppy. Uses two groups of EMAs to visualize the behavior of both traders (short-term) and investors (long-term).

Interpretation:
  • Short-term group fanning out above long-term group: Strong uptrend with trader and investor agreement.

  • Short-term group fanning out below long-term group: Strong downtrend.

  • Groups compressing: Trend weakening, consolidation.

  • Short-term crossing long-term: Trend change signal.

  • Wide separation between groups: Strong conviction.

  • Groups intertwined/overlapping: Indecision, no trend.

Returns two groups of EMAs:

  • Short-term group: 3, 5, 8, 10, 12, 15

  • Long-term group: 30, 35, 40, 45, 50, 60

Parameters:

data (Series) – Price series (typically close).

Returns:

Keys short_3, short_5, …, short_15, long_30, long_35, …, long_60.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> g = guppy_mma(pd.Series(np.random.randn(100).cumsum() + 100))
rainbow_ma(data, period=10, levels=10)[source]

Rainbow Moving Average – recursive SMAs.

Each level is an SMA of the previous level. Level 1 is SMA of data, level 2 is SMA of level 1, and so on.

Interpretation:
  • Price above all bands: Strong uptrend.

  • Price below all bands: Strong downtrend.

  • Bands fanning out: Trend strengthening.

  • Bands compressing: Trend weakening or consolidation.

  • Price touching inner bands then bouncing: Pullback buy/sell opportunity in the direction of the trend.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – SMA period applied at each level.

  • levels (int, default: 10) – Number of SMA recursions (typically 10).

Returns:

Keys sma_1 through sma_{levels}.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> rb = rainbow_ma(pd.Series(np.random.randn(100).cumsum() + 100))
hull_ma(data, period=16)[source]

Hull Moving Average (HMA).

HMA = WMA(2 * WMA(n/2) - WMA(n), sqrt(n))

Provides a fast, smooth moving average with reduced lag.

Interpretation:
  • Price above HMA: Bullish.

  • Price below HMA: Bearish.

  • HMA slope change: Early trend change signal. HMA turning up = bullish; turning down = bearish.

  • Extremely responsive due to the sqrt(n) final smoothing; excellent for short-term trend following.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 16) – HMA period.

Returns:

Hull Moving Average values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> hma = hull_ma(pd.Series(np.random.randn(100).cumsum() + 100), period=16)
zero_lag_ema(data, period=21)[source]

Zero-Lag Exponential Moving Average (ZLEMA).

Compensates for inherent EMA lag by applying the EMA to a de-lagged series: zlema_input = data + (data - data.shift(lag)) where lag = (period - 1) / 2.

Interpretation:
  • Same signals as EMA but with near-zero lag.

  • More responsive to recent price changes, giving earlier crossover signals.

  • Can overshoot in choppy markets due to the de-lagging adjustment.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 21) – EMA period.

Returns:

ZLEMA values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> zl = zero_lag_ema(pd.Series(np.random.randn(100).cumsum() + 100))
vidya(data, period=14, smooth=5)[source]

Variable Index Dynamic Average (VIDYA).

Uses the Chande Momentum Oscillator (CMO) as a volatility index to dynamically adjust the smoothing constant of an EMA.

Interpretation:
  • Behaves like a fast EMA in trending markets (high CMO) and a slow EMA in ranging markets (low CMO).

  • Price above VIDYA: Bullish trend.

  • Price below VIDYA: Bearish trend.

  • Less prone to whipsaws than standard EMA in choppy markets.

VIDYA_t = alpha * |CMO_t| * price_t + (1 - alpha * |CMO_t|) * VIDYA_{t-1}

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – CMO look-back period.

  • smooth (int, default: 5) – Smoothing period to derive the base alpha (2 / (smooth + 1)).

Returns:

VIDYA values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> v = vidya(pd.Series(np.random.randn(100).cumsum() + 100))
tilson_t3(data, period=5, volume_factor=0.7)[source]

Tilson T3 – triple-smoothed exponential moving average.

Applies six sequential EMAs with Tilson coefficients derived from the volume_factor to produce an ultra-smooth, low-lag average.

Interpretation:
  • Extremely smooth trend line with less lag than TEMA.

  • Price above T3: Bullish.

  • Price below T3: Bearish.

  • T3 slope change: Very reliable trend change signal due to the heavy smoothing.

  • Best for medium to long-term trend identification.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 5) – EMA period for each pass.

  • volume_factor (float, default: 0.7) – Volume factor (commonly 0.7). Controls the overshoot reduction.

Returns:

Tilson T3 values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> t3 = tilson_t3(pd.Series(np.random.randn(100).cumsum() + 100))
fractal_adaptive_ma(data, period=16)[source]

Fractal Adaptive Moving Average (FRAMA).

Uses the fractal dimension of the price series to dynamically adjust the EMA smoothing factor. More responsive in trending markets and slower during consolidation.

Interpretation:
  • Price above FRAMA: Bullish trend.

  • Price below FRAMA: Bearish trend.

  • Adapts automatically: becomes responsive (like short EMA) in trending markets and sluggish (like long EMA) during consolidation.

  • Excellent for trend following with automatic noise filtering.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 16) – Look-back period (should be even; if odd, it is rounded up).

Returns:

FRAMA values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> f = fractal_adaptive_ma(pd.Series(np.random.randn(200).cumsum() + 100))

Volatility Indicators

ATR, Bollinger Width, and OHLC-based volatility estimators.

Volatility indicators.

This module provides indicators that measure the degree of price variation over time. All functions accept pd.Series inputs and return pd.Series.

atr(high, low, close, period=14)[source]

Average True Range (ATR).

Uses the Wilder smoothing method (ewm(alpha=1/period)). The standard measure of market volatility.

Interpretation:
  • Higher ATR: More volatile market – wider price swings.

  • Lower ATR: Less volatile – tight price action.

  • Rising ATR: Volatility is increasing (often at trend beginnings or during strong moves).

  • Falling ATR: Volatility is decreasing (often during consolidation, before a breakout).

  • ATR does not indicate direction, only the magnitude of price movement.

Trading rules:
  • Stop placement: Set stop-loss at 2x or 3x ATR from entry to account for normal market noise.

  • Position sizing: Risk a fixed dollar amount per trade; divide by ATR to determine share count.

  • Breakout confirmation: A breakout with rising ATR is more likely to sustain than one with falling ATR.

  • Trailing stop: Trail by 2-3x ATR below the highest high (for longs).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Smoothing period.

Returns:

ATR values (always >= 0).

Return type:

Series

true_range(high, low, close)[source]

True Range.

TR = max(H - L, |H - C_prev|, |L - C_prev|)

The single-bar volatility measure that accounts for gaps.

Interpretation:
  • High TR: Large price movement – high volatility bar.

  • Low TR: Small price movement – low volatility bar.

  • Spikes in TR often occur at trend changes or breakouts.

  • TR forms the basis of ATR and many other volatility indicators.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

Returns:

True Range values (always >= 0).

Return type:

Series

natr(high, low, close, period=14)[source]

Normalized Average True Range (NATR).

NATR = (ATR / close) * 100

Interpretation:
  • Same as ATR but expressed as a percentage of price, making it comparable across different assets and price levels.

  • Higher NATR: More volatile (in percentage terms).

  • Lower NATR: Less volatile.

  • Useful for ranking assets by volatility or for building volatility-weighted portfolios.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – ATR period.

Returns:

NATR as a percentage.

Return type:

Series

bbwidth(data, period=20, std_dev=2.0)[source]

Bollinger Band Width.

BBWidth = (upper - lower) / middle

Interpretation:
  • Low BBWidth (squeeze): Bollinger Bands are narrow – volatility is low. A breakout is imminent. This is the key signal: low volatility precedes high volatility.

  • High BBWidth: Bollinger Bands are wide – volatility is high. The move may be overextended.

  • BBWidth at 6-month low: Strong squeeze – prepare for a significant breakout.

  • BBWidth expanding: Breakout in progress.

Trading rules:
  • Look for BBWidth at historical lows (squeeze).

  • When the squeeze releases (BBWidth starts expanding), trade the breakout direction.

  • Combine with momentum indicators to determine direction.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – SMA period.

  • std_dev (float, default: 2.0) – Number of standard deviations.

Returns:

Bandwidth values.

Return type:

Series

kc_width(high, low, close, period=20, multiplier=1.5)[source]

Keltner Channel Width.

KC_Width = (upper - lower) / middle

Interpretation:
  • Same concept as BBWidth but based on ATR instead of standard deviation.

  • Narrow KC Width: Low ATR volatility, potential squeeze.

  • Wide KC Width: High ATR volatility, extended move.

  • Used with BBWidth for the TTM Squeeze: when BB is inside KC, a squeeze is active.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – EMA / ATR period.

  • multiplier (float, default: 1.5) – ATR multiplier.

Returns:

Keltner Channel width values.

Return type:

Series

chaikin_volatility(high, low, period=10, smoothing=10)[source]

Chaikin Volatility.

Measures the rate of change of the EMA of the high-low spread.

Interpretation:
  • Rising: Volatility is increasing (range is expanding).

  • Falling: Volatility is decreasing (range is contracting).

  • Spike up: Can indicate a market top (panic/climax).

  • Spike down: Can indicate a market bottom (capitulation followed by quiet).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 10) – EMA smoothing period for the H-L spread.

  • smoothing (int, default: 10) – ROC period applied to the smoothed spread.

Returns:

Chaikin Volatility as a percentage.

Return type:

Series

historical_volatility(data, period=21, annualize=True)[source]

Historical Volatility (close-to-close).

Computes the rolling standard deviation of log returns. When annualize is True the result is scaled by sqrt(252).

Interpretation:
  • High HV (e.g. > 30% annualized for equities): Asset is highly volatile. Wider stops and smaller positions needed.

  • Low HV (e.g. < 15% annualized): Asset is calm. Tighter stops and larger positions possible.

  • HV vs Implied Volatility: If HV < IV, options are relatively expensive (sell premium). If HV > IV, options are cheap (buy premium).

  • Rising HV: Uncertainty increasing. Often accompanies selloffs.

  • Falling HV: Market calming down. Often accompanies gradual rallies.

Parameters:
  • data (Series) – Price series (close).

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

Returns:

Historical volatility (annualized if requested).

Return type:

Series

mass_index(high, low, period=9, trigger=25)[source]

Mass Index.

The Mass Index uses the high-low range to identify trend reversals based on range expansions. It accumulates the ratio of two EMAs of the range over the trigger period.

Interpretation:
  • Reversal bulge: The key signal. When Mass Index rises above 27 and then falls back below 26.5, a trend reversal is likely (regardless of direction).

  • The indicator does not tell you the direction of the reversal, only that one is coming.

  • Combine with a trend indicator to determine which direction the reversal will take.

Trading rules:
  • When Mass Index crosses above 27 then back below 26.5 (reversal bulge), prepare for a trend change.

  • Use a 9-period EMA crossover or similar to determine the new trend direction.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 9) – EMA period for the range.

  • trigger (int, default: 25) – Summation (rolling sum) window.

Returns:

Mass Index values. A reversal bulge occurs when the index rises above 27 and then falls below 26.5.

Return type:

Series

garman_klass(high, low, close, open_, period=21, annualize=True)[source]

Garman-Klass volatility estimator.

An efficient OHLC volatility estimator that uses open, high, low, and close prices. More efficient than close-to-close because it uses intraday range information.

Interpretation:
  • Values are directly comparable to historical volatility.

  • Higher efficiency: Uses the same data as close-to-close but extracts more information, producing tighter estimates.

  • Compare with Parkinson and Yang-Zhang to assess which estimator best suits your data.

  • Does not handle overnight gaps well; use Yang-Zhang for assets with significant overnight risk.

GK = sqrt((1/n) * sum(0.5*(ln(H/L))^2 - (2*ln(2)-1)*(ln(C/O))^2))

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open (pd.Series) – Open prices.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

  • open_ (Series)

Returns:

Garman-Klass volatility estimate.

Return type:

Series

Example

>>> gk = garman_klass(high, low, close, open_, period=21)
Parameters:
Return type:

Series

parkinson(high, low, period=21, annualize=True)[source]

Parkinson volatility estimator.

Uses the high-low range to estimate volatility, which is more efficient than close-to-close since it captures intraday extremes.

Interpretation:
  • Approximately 5x more efficient than close-to-close.

  • Tends to underestimate true volatility when there are overnight gaps (since it ignores open/close).

  • Best suited for assets that trade continuously (e.g. forex).

Parkinson = sqrt((1 / (4 * n * ln(2))) * sum((ln(H/L))^2))

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

Returns:

Parkinson volatility estimate.

Return type:

Series

Example

>>> pk = parkinson(high, low, period=21)
rogers_satchell(high, low, close, open_, period=21, annualize=True)[source]

Rogers-Satchell volatility estimator.

Accounts for non-zero drift (trending markets), making it more robust than Parkinson or Garman-Klass for trending assets.

Interpretation:
  • Better than Garman-Klass for assets with strong trends, because it does not assume zero drift.

  • Still does not handle overnight gaps; for that, use Yang-Zhang.

RS = sqrt((1/n) * sum(ln(H/C)*ln(H/O) + ln(L/C)*ln(L/O)))

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open (pd.Series) – Open prices.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

  • open_ (Series)

Returns:

Rogers-Satchell volatility estimate.

Return type:

Series

Example

>>> rs = rogers_satchell(high, low, close, open_, period=21)
Parameters:
Return type:

Series

yang_zhang(high, low, close, open_, period=21, annualize=True)[source]

Yang-Zhang volatility estimator.

The most efficient OHLC volatility estimator. Combines overnight (close-to-open) volatility, open-to-close volatility, and the Rogers-Satchell estimator.

Interpretation:
  • The gold standard for OHLC volatility estimation.

  • Handles both overnight gaps and intraday drift.

  • Use this as the default volatility estimator when you have full OHLC data.

  • Compare with close-to-close: if Yang-Zhang is significantly higher, overnight/gap risk is material.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open (pd.Series) – Open prices.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

  • open_ (Series)

Returns:

Yang-Zhang volatility estimate.

Return type:

Series

Example

>>> yz = yang_zhang(high, low, close, open_, period=21)
Parameters:
Return type:

Series

close_to_close(data, period=21, annualize=True)[source]

Close-to-close volatility (standard deviation of log returns).

The simplest volatility estimator based on daily log returns. This is equivalent to historical_volatility() but named explicitly to distinguish it from range-based estimators.

Interpretation:
  • The baseline volatility measure. All other estimators (Parkinson, Garman-Klass, Yang-Zhang) should be compared against this.

  • See historical_volatility() for full interpretation.

Parameters:
  • data (Series) – Close price series.

  • period (int, default: 21) – Rolling window.

  • annualize (bool, default: True) – If True, multiply by sqrt(252).

Returns:

Close-to-close volatility.

Return type:

Series

Example

>>> cc = close_to_close(close, period=21)
ulcer_index(data, period=14)[source]

Ulcer Index.

Measures downside volatility by computing the quadratic mean of percentage drawdowns from the rolling maximum over the given period. Higher values indicate greater drawdown depth and duration.

Interpretation:
  • Low values (< 5): Stable asset with shallow drawdowns.

  • High values (> 10): Asset is experiencing significant drawdowns.

  • Unlike standard deviation, only measures downside risk.

  • Used in the Martin Ratio (return / Ulcer Index) as a risk-adjusted performance metric.

  • Rising Ulcer Index = drawdowns are deepening = trouble.

UI = sqrt(mean(R^2)) where R = 100 * (C - max(C, n)) / max(C, n)

Parameters:
  • data (Series) – Close price series.

  • period (int, default: 14) – Rolling window.

Returns:

Ulcer Index values (always >= 0).

Return type:

Series

Example

>>> ui = ulcer_index(close, period=14)
relative_volatility_index(data, period=10, smoothing=14)[source]

Relative Volatility Index (RVI).

Applies the RSI formula to the rolling standard deviation of closes rather than to price changes.

Interpretation:
  • > 50: Volatility is increasing (standard deviation is rising) – directional moves are more likely.

  • < 50: Volatility is decreasing (standard deviation is falling) – consolidation / range-bound.

  • Not a standalone indicator; best used as a filter.

Trading rules:
  • Confirm RSI signals: only take RSI buy signals when RVI > 50.

  • Avoid breakout trades when RVI < 50 (low volatility = false breakout risk).

Parameters:
  • data (Series) – Close price series.

  • period (int, default: 10) – Standard deviation lookback.

  • smoothing (int, default: 14) – RSI-style smoothing period applied to the std-dev changes.

Returns:

RVI values oscillating between 0 and 100.

Return type:

Series

Example

>>> rvi = relative_volatility_index(close, period=10, smoothing=14)
acceleration_bands(high, low, close, period=20, factor=0.001)[source]

Acceleration Bands.

Bands that widen with high-low range acceleration, narrowing during consolidation. Uses factor * (high - low) / (high + low) as the width multiplier.

Interpretation:
  • Price above upper band: Strong uptrend / breakout.

  • Price below lower band: Strong downtrend / breakdown.

  • Bands narrowing: Consolidation – breakout imminent.

  • Bands widening: Trend accelerating.

  • Similar concept to Bollinger Bands but based on range acceleration rather than standard deviation.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 20) – SMA period.

  • factor (float, default: 0.001) – Width factor applied to range acceleration.

Returns:

Dictionary with keys "upper", "middle", "lower".

Return type:

dict[str, Series]

Example

>>> bands = acceleration_bands(high, low, close, period=20)
>>> upper = bands["upper"]
standard_deviation(data, period=20)[source]

Rolling standard deviation.

Computes the rolling sample standard deviation over the given period.

Interpretation:
  • Rising: Volatility increasing – larger price swings.

  • Falling: Volatility decreasing – tighter price action.

  • Low standard deviation often precedes a breakout.

  • Used to compute Bollinger Bands (middle +/- N * std_dev).

Parameters:
  • data (Series) – Input price series.

  • period (int, default: 20) – Rolling window.

Returns:

Rolling standard deviation values.

Return type:

Series

Example

>>> sd = standard_deviation(close, period=20)
variance(data, period=20)[source]

Rolling variance.

Computes the rolling sample variance over the given period.

Interpretation:
  • The square of standard deviation. Same directional interpretation as standard deviation.

  • Useful in mathematical contexts where variance is preferred (e.g. portfolio optimization, risk decomposition).

Parameters:
  • data (Series) – Input price series.

  • period (int, default: 20) – Rolling window.

Returns:

Rolling variance values.

Return type:

Series

Example

>>> v = variance(close, period=20)

Pattern Recognition

38 candlestick patterns returning boolean match Series.

Candlestick pattern recognition.

Each function returns a pd.Series of integers:

  • 1 — bullish signal

  • -1 — bearish signal

  • 0 — no pattern detected

Some patterns are inherently one-directional (e.g. Morning Star is always bullish), but where a pattern has both bullish and bearish variants the sign distinguishes them.

doji(open_, high, low, close, threshold=0.05)[source]

Doji pattern.

A Doji occurs when the body is very small relative to the total range.

Interpretation:
  • Indecision: Open and close are nearly equal – buyers and sellers are in balance.

  • At resistance: Bearish signal (potential reversal down).

  • At support: Bullish signal (potential reversal up).

  • In a trend: Warning that momentum may be fading.

  • Requires confirmation from the next candle – a doji alone is not a signal.

  • Reliability: Moderate. More significant after a strong trend.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.05) – Maximum body-to-range ratio to qualify as a Doji.

  • open_ (Series)

Returns:

1 where a Doji is detected, 0 otherwise.

Return type:

Series

hammer(open_, high, low, close)[source]

Hammer and Hanging Man pattern.

A hammer has a small body near the top and a long lower shadow (at least 2x the body). Returns 1 for bullish hammer (after a downtrend proxy: prior close < close), -1 for hanging man (after an uptrend proxy: prior close > close), 0 otherwise.

Interpretation:
  • Hammer (1): Bullish reversal after a downtrend. Sellers pushed price down during the session but buyers fought back, closing near the open. The long lower shadow shows rejected selling pressure.

  • Hanging Man (-1): Bearish warning after an uptrend. Same shape, but context differs – suggests sellers are emerging.

  • Confirmation needed: Wait for the next candle to close in the reversal direction.

  • Reliability: High for hammers at major support levels.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 (bullish hammer), -1 (hanging man), or 0.

Return type:

Series

engulfing(open_, high, low, close)[source]

Bullish/Bearish Engulfing pattern.

Interpretation:
  • Bullish engulfing (1): A small bearish candle completely engulfed by a larger bullish candle. Strong reversal signal at the bottom of a downtrend.

  • Bearish engulfing (-1): A small bullish candle completely engulfed by a larger bearish candle. Strong reversal signal at the top of an uptrend.

  • Volume confirmation strengthens the signal.

  • Reliability: High – one of the most reliable reversal patterns, especially at key support/resistance levels.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 (bullish engulfing), -1 (bearish engulfing), or 0.

Return type:

Series

morning_star(open_, high, low, close)[source]

Morning Star (3-candle bullish reversal).

Interpretation:
  • A strong bullish reversal signal at the bottom of a downtrend.

  • Day 1 (large bearish): Bears are in control.

  • Day 2 (small body / doji): Indecision – selling pressure is exhausting.

  • Day 3 (large bullish): Bulls take over, closing above the midpoint of Day 1’s body.

  • Reliability: High – three-candle confirmation reduces false signals. Best at established support levels.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 where a Morning Star is detected, 0 otherwise.

Return type:

Series

evening_star(open_, high, low, close)[source]

Evening Star (3-candle bearish reversal).

Interpretation:
  • The bearish counterpart of the Morning Star.

  • Day 1 (large bullish): Bulls are in control.

  • Day 2 (small body / doji): Indecision at the top.

  • Day 3 (large bearish): Bears take over.

  • Reliability: High – the mirror of Morning Star. Best at established resistance levels.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

-1 where an Evening Star is detected, 0 otherwise.

Return type:

Series

three_white_soldiers(open_, high, low, close)[source]

Three White Soldiers (strong bullish continuation).

Three consecutive bullish candles, each opening within the prior body and closing at a new high.

Interpretation:
  • Strong bullish signal indicating sustained buying pressure.

  • Each candle should have a full body (not spinning tops).

  • Best after a downtrend or consolidation as a reversal signal.

  • Reliability: Very high – three consecutive strong closes show committed buying. Weakened if upper shadows are long (advance block pattern).

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 where the pattern is detected, 0 otherwise.

Return type:

Series

three_black_crows(open_, high, low, close)[source]

Three Black Crows (strong bearish continuation).

Three consecutive bearish candles, each opening within the prior body and closing at a new low.

Interpretation:
  • Strong bearish signal indicating sustained selling pressure.

  • The bearish counterpart of Three White Soldiers.

  • Reliability: Very high – three consecutive strong closes downward show committed selling.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

-1 where the pattern is detected, 0 otherwise.

Return type:

Series

harami(open_, high, low, close)[source]

Harami pattern (bullish and bearish).

The second candle’s body is entirely contained within the first candle’s body.

Interpretation:
  • Bullish harami (1): A large bearish candle followed by a small bullish candle within its body. Suggests selling pressure is weakening. Reversal may follow.

  • Bearish harami (-1): A large bullish candle followed by a small bearish candle within its body. Suggests buying pressure is weakening.

  • Reliability: Moderate – requires confirmation from the following candle. Less reliable than engulfing patterns.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 (bullish harami), -1 (bearish harami), or 0.

Return type:

Series

spinning_top(open_, high, low, close, body_threshold=0.3)[source]

Spinning Top (indecision candle).

A candle with a small body relative to its range and roughly equal upper and lower shadows.

Interpretation:
  • Indecision: Neither buyers nor sellers gained control.

  • In an uptrend: Warns that bulls are losing momentum.

  • In a downtrend: Warns that bears are losing momentum.

  • Not a reversal signal on its own – needs confirmation.

  • Reliability: Low as a standalone signal; moderate when appearing at key levels after a sustained trend.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.3) – Maximum body-to-range ratio.

  • open_ (Series)

Returns:

1 where a Spinning Top is detected, 0 otherwise.

Return type:

Series

marubozu(open_, high, low, close, threshold=0.01)[source]

Marubozu (full-body candle with no/tiny wicks).

Interpretation:
  • Bullish marubozu (1): Opens at the low and closes at the high – buyers dominated the entire session with no pushback. Very strong bullish conviction.

  • Bearish marubozu (-1): Opens at the high and closes at the low – sellers dominated completely.

  • Reliability: High – the absence of shadows shows one side had complete control. Often marks the beginning of a new trend leg.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.01) – Maximum shadow-to-range ratio for each shadow.

  • open_ (Series)

Returns:

1 (bullish marubozu), -1 (bearish marubozu), or 0.

Return type:

Series

piercing_pattern(open_, high, low, close)[source]

Piercing Pattern (bullish reversal).

A two-candle pattern: Day 1 is bearish, Day 2 opens below Day 1’s low and closes above the midpoint of Day 1’s body.

Interpretation:
  • Bullish reversal signal at the bottom of a downtrend.

  • The gap down open followed by a strong close above the midpoint shows buyers stepping in aggressively.

  • Reliability: Moderate-high. Stronger when the close is deeper into Day 1’s body (closer to engulfing).

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 where a Piercing Pattern is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = piercing_pattern(open_, high, low, close)
Parameters:
Return type:

Series

dark_cloud_cover(open_, high, low, close)[source]

Dark Cloud Cover (bearish reversal).

The bearish counterpart of the Piercing Pattern. Day 1 is bullish, Day 2 opens above Day 1’s high and closes below the midpoint of Day 1’s body.

Interpretation:
  • Bearish reversal signal at the top of an uptrend.

  • The gap up open followed by selling down into Day 1’s body shows sellers overpowering buyers.

  • Reliability: Moderate-high. More significant with high volume.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

-1 where a Dark Cloud Cover is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = dark_cloud_cover(open_, high, low, close)
Parameters:
Return type:

Series

hanging_man(open_, high, low, close, trend_period=5)[source]

Hanging Man (bearish reversal at top).

Same hammer shape (small body near top, long lower shadow) but appears after an uptrend, signalling potential reversal.

Interpretation:
  • Bearish warning signal after an uptrend. The long lower shadow shows sellers tested lower prices during the session.

  • Needs confirmation: a bearish close the next day confirms the reversal.

  • Reliability: Moderate – requires confirmation and context.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • trend_period (int, default: 5) – Number of bars to assess prior uptrend.

  • open_ (Series)

Returns:

-1 where a Hanging Man is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = hanging_man(open_, high, low, close)
Parameters:
Return type:

Series

inverted_hammer(open_, high, low, close, trend_period=5)[source]

Inverted Hammer (bullish reversal at bottom).

A candle with a long upper shadow (at least 2x the body) and a small lower shadow, appearing after a downtrend.

Interpretation:
  • Bullish reversal signal at the bottom of a downtrend.

  • The long upper shadow shows buyers tested higher prices but could not hold them yet. If confirmed by next bar, buyers are gaining strength.

  • Reliability: Moderate – requires a bullish confirmation candle the next day.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • trend_period (int, default: 5) – Number of bars to assess prior downtrend.

  • open_ (Series)

Returns:

1 where an Inverted Hammer is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = inverted_hammer(open_, high, low, close)
Parameters:
Return type:

Series

shooting_star(open_, high, low, close, trend_period=5)[source]

Shooting Star (bearish reversal at top).

Same shape as inverted hammer (long upper shadow, small lower shadow) but appears after an uptrend.

Interpretation:
  • Bearish reversal signal at the top of an uptrend. Buyers pushed price higher but sellers overwhelmed them, closing near the open.

  • The long upper shadow represents rejected higher prices.

  • Reliability: Moderate-high – stronger when it appears at resistance with high volume.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • trend_period (int, default: 5) – Number of bars to assess prior uptrend.

  • open_ (Series)

Returns:

-1 where a Shooting Star is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = shooting_star(open_, high, low, close)
Parameters:
Return type:

Series

tweezer_top(open_, high, low, close, tolerance=0.001)[source]

Tweezer Top (bearish reversal).

Two consecutive candles with nearly the same highs. The first candle is bullish and the second is bearish.

Interpretation:
  • Bearish reversal at a resistance level. Both candles tested the same high and were rejected, showing strong resistance.

  • Reliability: Moderate – stronger at established resistance.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.001) – Maximum relative difference between highs to be considered equal.

  • open_ (Series)

Returns:

-1 where a Tweezer Top is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = tweezer_top(open_, high, low, close)
Parameters:
Return type:

Series

tweezer_bottom(open_, high, low, close, tolerance=0.001)[source]

Tweezer Bottom (bullish reversal).

Two consecutive candles with nearly the same lows. The first candle is bearish and the second is bullish.

Interpretation:
  • Bullish reversal at a support level. Both candles tested the same low and were rejected, showing strong support.

  • Reliability: Moderate – stronger at established support.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.001) – Maximum relative difference between lows to be considered equal.

  • open_ (Series)

Returns:

1 where a Tweezer Bottom is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = tweezer_bottom(open_, high, low, close)
Parameters:
Return type:

Series

three_inside_up(open_, high, low, close)[source]

Three Inside Up (bullish reversal).

A three-candle pattern: bullish harami (Days 1-2) confirmed by a third bullish candle closing above Day 1’s open.

Interpretation:
  • A confirmed bullish harami. The third candle provides the confirmation that a simple harami lacks.

  • Reliability: High – three-candle confirmation is stronger than the two-candle harami alone.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 where the pattern is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = three_inside_up(open_, high, low, close)
Parameters:
Return type:

Series

three_inside_down(open_, high, low, close)[source]

Three Inside Down (bearish reversal).

A three-candle pattern: bearish harami (Days 1-2) confirmed by a third bearish candle closing below Day 1’s open.

Interpretation:
  • A confirmed bearish harami. The bearish counterpart of Three Inside Up.

  • Reliability: High – three-candle confirmation pattern.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

-1 where the pattern is detected, 0 otherwise.

Return type:

Series

Example

>>> signal = three_inside_down(open_, high, low, close)
Parameters:
Return type:

Series

abandoned_baby(open_, high, low, close)[source]

Abandoned Baby (reversal pattern).

A rare three-candle pattern with gaps. A Doji star gaps away from the first candle and the third candle gaps in the opposite direction.

Interpretation:
  • Bullish abandoned baby (1): Bearish candle, gap-down doji, gap-up bullish candle. Very strong reversal signal.

  • Bearish abandoned baby (-1): Bullish candle, gap-up doji, gap-down bearish candle. Very strong reversal signal.

  • Reliability: Very high – but extremely rare. The gap isolation of the doji shows a dramatic sentiment shift.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Returns:

1 (bullish abandoned baby), -1 (bearish abandoned baby), or 0.

Return type:

Series

Example

>>> signal = abandoned_baby(open_, high, low, close)
Parameters:
Return type:

Series

kicking(open_, high, low, close, threshold=0.01)[source]

Kicking pattern.

Two consecutive marubozu candles in opposite directions with a gap between them. One of the strongest reversal signals.

Interpretation:
  • Bullish kicking (1): Bearish marubozu followed by a gap-up bullish marubozu. Extremely strong reversal.

  • Bearish kicking (-1): Bullish marubozu followed by a gap-down bearish marubozu.

  • Reliability: Very high – one of the most powerful candlestick patterns. The opposing full-body candles with a gap show a complete and sudden sentiment reversal.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.01) – Maximum shadow-to-range ratio for marubozu qualification.

  • open_ (Series)

Returns:

1 (bullish kicking), -1 (bearish kicking), or 0.

Return type:

Series

Example

>>> signal = kicking(open_, high, low, close)
Parameters:
Return type:

Series

belt_hold(open_, high, low, close, threshold=0.01)[source]

Belt Hold pattern.

A long marubozu candle that opens with a gap in the direction of the prior trend. A bullish belt hold gaps down and opens at the low; a bearish belt hold gaps up and opens at the high.

Interpretation:
  • Bullish belt hold (1): Gaps down then rallies all day closing near the high – strong rejection of lower prices.

  • Bearish belt hold (-1): Gaps up then sells off all day.

  • Reliability: Moderate – the gap adds significance.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.01) – Maximum shadow-to-range ratio for the relevant shadow.

  • open_ (Series)

Returns:

1 (bullish belt hold), -1 (bearish belt hold), or 0.

Return type:

Series

Example

>>> signal = belt_hold(open_, high, low, close)
Parameters:
Return type:

Series

rising_three_methods(open_, high, low, close)[source]

Rising Three Methods (bullish continuation).

A five-candle pattern: a long bullish candle, followed by three small bearish candles that stay within the first candle’s range, then a final long bullish candle that closes above the first candle’s close.

Interpretation:
  • Bullish continuation pattern – the three small bearish candles are a rest/consolidation within the uptrend.

  • The final bullish candle confirms the trend resumes.

  • Reliability: High – five-candle confirmation shows clear trend continuation with a healthy pullback.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 where the pattern is detected, 0 otherwise.

Example

>>> signal = rising_three_methods(open_, high, low, close)
Parameters:
Return type:

Series

falling_three_methods(open_, high, low, close)[source]

Falling Three Methods (bearish continuation).

The bearish counterpart of Rising Three Methods. A long bearish candle, three small bullish candles inside its range, then a final long bearish candle that closes below the first candle’s close.

Interpretation:
  • Bearish continuation pattern – the small bullish candles are a brief consolidation within the downtrend.

  • Reliability: High – mirror of Rising Three Methods.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

-1 where the pattern is detected, 0 otherwise.

Example

>>> signal = falling_three_methods(open_, high, low, close)
Parameters:
Return type:

Series

tasuki_gap(open_, high, low, close)[source]

Upside/Downside Tasuki Gap.

Upside (1): two bullish candles with a gap up, followed by a bearish candle that opens within the second body and closes within the gap but does not fill it.

Downside (-1): two bearish candles with a gap down, followed by a bullish candle that opens within the second body and closes within the gap but does not fill it.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 (upside Tasuki gap), -1 (downside Tasuki gap), or 0.

Example

>>> signal = tasuki_gap(open_, high, low, close)
Parameters:
Return type:

Series

on_neck(open_, high, low, close, tolerance=0.001)[source]

On Neck pattern (bearish continuation).

A bearish candle followed by a small bullish candle that opens below the previous low and closes at or near the previous low.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.001) – Maximum relative difference between close and previous low.

  • open_ (Series)

Return type:

Series

Returns:

-1 where the pattern is detected, 0 otherwise.

Example

>>> signal = on_neck(open_, high, low, close)
Parameters:
Return type:

Series

in_neck(open_, high, low, close, tolerance=0.003)[source]

In Neck pattern (slight bullish variant of On Neck).

A bearish candle followed by a small bullish candle that opens below the previous low and closes slightly above (but near) the previous close.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.003) – Maximum relative distance above the previous close.

  • open_ (Series)

Return type:

Series

Returns:

-1 where the pattern is detected, 0 otherwise.

Example

>>> signal = in_neck(open_, high, low, close)
Parameters:
Return type:

Series

thrusting(open_, high, low, close)[source]

Thrusting pattern (moderate bearish continuation).

A bearish candle followed by a bullish candle that opens below the previous low and closes above the previous close but below the midpoint of the previous body.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

-1 where the pattern is detected, 0 otherwise.

Example

>>> signal = thrusting(open_, high, low, close)
Parameters:
Return type:

Series

separating_lines(open_, high, low, close, tolerance=0.001)[source]

Bullish/Bearish Separating Lines.

Bullish (1): a bearish candle followed by a bullish candle that opens at the same level as the previous open.

Bearish (-1): a bullish candle followed by a bearish candle that opens at the same level as the previous open.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • tolerance (float, default: 0.001) – Maximum relative difference between opens.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish), -1 (bearish), or 0.

Example

>>> signal = separating_lines(open_, high, low, close)
Parameters:
Return type:

Series

closing_marubozu(open_, high, low, close, threshold=0.01)[source]

Closing Marubozu — no shadow on the closing side only.

A bullish closing marubozu (1) has no upper shadow (close == high) but may have a lower shadow. A bearish closing marubozu (-1) has no lower shadow (close == low) but may have an upper shadow.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • threshold (float, default: 0.01) – Maximum shadow-to-range ratio for the closing side.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish), -1 (bearish), or 0.

Example

>>> signal = closing_marubozu(open_, high, low, close)
Parameters:
Return type:

Series

rickshaw_man(open_, high, low, close, body_threshold=0.05, shadow_threshold=0.3)[source]

Rickshaw Man – a Doji with very long shadows and tiny body near center.

Interpretation:
  • Extreme indecision: price moved significantly in both directions but closed near the open at the midpoint.

  • Suggests the market is at a critical juncture.

  • Reliability: Moderate – needs context and confirmation.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.05) – Maximum body-to-range ratio to qualify.

  • shadow_threshold (float, default: 0.3) – Minimum shadow-to-range ratio for each shadow.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = rickshaw_man(open_, high, low, close)
Parameters:
Return type:

Series

long_legged_doji(open_, high, low, close, body_threshold=0.05, shadow_threshold=0.3)[source]

Long Legged Doji – Doji with unusually long upper and lower shadows.

Interpretation:
  • Strong indecision with high volatility. Both buyers and sellers were active but neither won.

  • More significant than a standard doji due to the wide range.

  • Reliability: Moderate – similar to Rickshaw Man.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.05) – Maximum body-to-range ratio.

  • shadow_threshold (float, default: 0.3) – Minimum shadow-to-range ratio for each shadow.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = long_legged_doji(open_, high, low, close)
Parameters:
Return type:

Series

dragonfly_doji(open_, high, low, close, body_threshold=0.05, upper_threshold=0.05, lower_min=0.3)[source]

Dragonfly Doji – Doji with a long lower shadow and no upper shadow.

Interpretation:
  • Bullish signal, especially after a downtrend. Sellers pushed price down but buyers brought it all the way back to the open.

  • The long lower shadow shows strong rejection of lower prices.

  • Reliability: Moderate-high at support levels.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.05) – Maximum body-to-range ratio.

  • upper_threshold (float, default: 0.05) – Maximum upper-shadow-to-range ratio.

  • lower_min (float, default: 0.3) – Minimum lower-shadow-to-range ratio.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = dragonfly_doji(open_, high, low, close)
Parameters:
Return type:

Series

gravestone_doji(open_, high, low, close, body_threshold=0.05, lower_threshold=0.05, upper_min=0.3)[source]

Gravestone Doji – Doji with a long upper shadow and no lower shadow.

Interpretation:
  • Bearish signal, especially after an uptrend. Buyers pushed price up but sellers brought it all the way back to the open.

  • The long upper shadow shows strong rejection of higher prices.

  • Reliability: Moderate-high at resistance levels.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_threshold (float, default: 0.05) – Maximum body-to-range ratio.

  • lower_threshold (float, default: 0.05) – Maximum lower-shadow-to-range ratio.

  • upper_min (float, default: 0.3) – Minimum upper-shadow-to-range ratio.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = gravestone_doji(open_, high, low, close)
Parameters:
Return type:

Series

tri_star(open_, high, low, close, doji_threshold=0.05)[source]

Tri-Star pattern – three consecutive dojis with gaps.

Interpretation:
  • Bullish tri-star (1): Three dojis where the middle gaps below. Very rare, strong reversal at bottoms.

  • Bearish tri-star (-1): Three dojis where the middle gaps above. Very rare, strong reversal at tops.

  • Reliability: Very high when it occurs, but extremely rare.

Bullish (1): three dojis where the middle gaps below the other two. Bearish (-1): three dojis where the middle gaps above the other two.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • doji_threshold (float, default: 0.05) – Maximum body-to-range ratio for doji qualification.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish tri-star), -1 (bearish tri-star), or 0.

Example

>>> signal = tri_star(open_, high, low, close)
Parameters:
Return type:

Series

unique_three_river(open_, high, low, close)[source]

Unique Three River Bottom (rare bullish reversal).

Day 1: long bearish candle. Day 2: harami-like bearish candle with a lower low. Day 3: small bullish candle that closes below Day 2’s close.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 where detected, 0 otherwise.

Example

>>> signal = unique_three_river(open_, high, low, close)
Parameters:
Return type:

Series

concealing_baby_swallow(open_, high, low, close, marubozu_threshold=0.02)[source]

Concealing Baby Swallow (four-candle bearish pattern).

Four bearish candles: Days 1-2 are bearish marubozus. Day 3 gaps down, has a long upper shadow into Day 2’s body. Day 4 engulfs Day 3 including the shadow.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • marubozu_threshold (float, default: 0.02) – Maximum shadow-to-range ratio for marubozu.

  • open_ (Series)

Return type:

Series

Returns:

-1 where detected, 0 otherwise.

Example

>>> signal = concealing_baby_swallow(open_, high, low, close)
Parameters:
Return type:

Series

Signal Generation

Utility functions for combining indicators: crossover, crossunder, above, below, rising, falling.

Signal generation utilities.

Helper functions for detecting crossovers, comparing series, and computing rolling extremes. These are the building blocks used to translate indicator values into actionable trading signals.

crossover(series1, series2)[source]

Detect when series1 crosses above series2.

Interpretation:
  • Returns True on the exact bar where series1 moves from below-or-equal to above series2.

  • Common uses: MA crossovers, RSI crossing above 30, MACD crossing above signal line.

  • Only fires on the transition bar, not on subsequent bars where series1 remains above series2.

Parameters:
  • series1 (Series) – First data series.

  • series2 (Series | float | int) – Second data series or constant level.

Returns:

Boolean series — True on bars where series1 crosses above series2.

Return type:

Series

crossunder(series1, series2)[source]

Detect when series1 crosses below series2.

Interpretation:
  • Returns True on the exact bar where series1 moves from above-or-equal to below series2.

  • Common uses: MA death crosses, RSI crossing below 70, MACD crossing below signal line.

Parameters:
  • series1 (Series) – First data series.

  • series2 (Series | float | int) – Second data series or constant level.

Returns:

Boolean series — True on bars where series1 crosses below series2.

Return type:

Series

above(series1, series2)[source]

Element-wise series1 > series2.

Parameters:
  • series1 (Series) – First data series.

  • series2 (Series | float | int) – Second data series or constant level.

Returns:

Boolean series.

Return type:

Series

below(series1, series2)[source]

Element-wise series1 < series2.

Parameters:
  • series1 (Series) – First data series.

  • series2 (Series | float | int) – Second data series or constant level.

Returns:

Boolean series.

Return type:

Series

rising(data, period=1)[source]

Detect whether data is rising (each bar higher than period bars ago).

Parameters:
  • data (Series) – Data series.

  • period (int, default: 1) – Number of bars to look back.

Returns:

Boolean series.

Return type:

Series

falling(data, period=1)[source]

Detect whether data is falling (each bar lower than period bars ago).

Parameters:
  • data (Series) – Data series.

  • period (int, default: 1) – Number of bars to look back.

Returns:

Boolean series.

Return type:

Series

highest(data, period=14)[source]

Rolling highest value over period bars.

Parameters:
  • data (Series) – Data series.

  • period (int, default: 14) – Rolling window size.

Returns:

Rolling maximum.

Return type:

Series

lowest(data, period=14)[source]

Rolling lowest value over period bars.

Parameters:
  • data (Series) – Data series.

  • period (int, default: 14) – Rolling window size.

Returns:

Rolling minimum.

Return type:

Series

normalize(data, period=None)[source]

Z-score normalization.

When period is None, the full-series mean and standard deviation are used. When period is given, a rolling z-score is computed.

Parameters:
  • data (Series) – Data series.

  • period (int | None, default: None) – Rolling window for mean/std. None uses the entire series.

Returns:

Z-score normalized values.

Return type:

Series

Statistical Functions

Z-score, percentile rank, skewness, kurtosis, Hurst exponent, rolling beta, R-squared.

Statistical technical analysis indicators.

This module provides rolling statistical measures commonly used in quantitative analysis and systematic trading. All functions accept pd.Series inputs and return pd.Series.

zscore(data, period=20)[source]

Rolling z-score of price.

Measures how many standard deviations the current value is from the rolling mean.

Interpretation:
  • > +2: Price is 2+ standard deviations above mean – statistically unusual (overbought).

  • < -2: Price is 2+ standard deviations below mean – statistically unusual (oversold).

  • Near 0: Price is near its rolling average (fair value).

  • Mean-reversion traders buy at z < -2 and sell at z > +2.

  • In trending markets, z-score can stay extreme for extended periods – use with a trend filter.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Z-score values (unbounded).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13])
>>> zscore(close, period=5)
percentile_rank(data, period=20)[source]

Rolling percentile rank.

Computes the percentage of values within the rolling window that are less than or equal to the current value.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Percentile rank in [0, 100].

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13])
>>> percentile_rank(close, period=5)
mean_deviation(data, period=20)[source]

Rolling mean absolute deviation.

Computes the average of absolute deviations from the rolling mean.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Mean absolute deviation values (>= 0).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13])
>>> mean_deviation(close, period=5)
median(data, period=20)[source]

Rolling median.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Rolling median values.

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13])
>>> median(close, period=5)
skewness(data, period=20)[source]

Rolling skewness.

Measures the asymmetry of the distribution of values within the rolling window. Uses Fisher’s definition (bias-corrected).

Interpretation:
  • Positive skew: Distribution has a long right tail – occasional large positive moves (typical of call option payoffs).

  • Negative skew: Distribution has a long left tail – occasional large negative moves (crash risk).

  • Near 0: Symmetric distribution (normal-like).

  • Negative skew in returns is common for equities – tail risk is to the downside.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length (must be >= 3).

Returns:

Skewness values (unbounded).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series(range(30), dtype=float)
>>> skewness(close, period=20)
kurtosis(data, period=20)[source]

Rolling kurtosis (excess kurtosis, Fisher’s definition).

Measures the tailedness of the distribution of values within the rolling window. Normal distribution has excess kurtosis of 0.

Interpretation:
  • > 0 (leptokurtic): Fatter tails than normal – more extreme moves than a Gaussian would predict. Common in financial returns.

  • < 0 (platykurtic): Thinner tails than normal – fewer extreme moves.

  • Near 0 (mesokurtic): Normal-like tail behavior.

  • High kurtosis warns of tail risk – standard VaR and Gaussian-based risk models will underestimate risk.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length (must be >= 4).

Returns:

Excess kurtosis values (unbounded).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series(range(30), dtype=float)
>>> kurtosis(close, period=20)
entropy(data, period=20, bins=10)[source]

Rolling Shannon entropy of binned price changes.

Discretises the price changes within the rolling window into bins equal-width bins and computes Shannon entropy in nats (natural log).

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Rolling window length.

  • bins (int, default: 10) – Number of histogram bins for discretisation.

Returns:

Shannon entropy values (>= 0).

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series(range(30), dtype=float)
>>> entropy(close, period=20, bins=5)
hurst_exponent(data, period=100)[source]

Rolling Hurst exponent via the rescaled range (R/S) method.

  • H < 0.5: mean-reverting

  • H = 0.5: random walk

  • H > 0.5: trending

Parameters:
  • data (Series) – Price series.

  • period (int, default: 100) – Rolling window length (should be >= 20 for reliable estimates).

Returns:

Hurst exponent estimates in roughly [0, 1].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> close = pd.Series(100 + np.cumsum(np.random.randn(200)))
>>> hurst_exponent(close, period=100)
correlation(data, other, period=20)[source]

Rolling Pearson correlation between two series.

Parameters:
  • data (Series) – First price series.

  • other (Series) – Second price series.

  • period (int, default: 20) – Rolling window length.

Returns:

Correlation values in [-1, 1].

Return type:

Series

Example

>>> import pandas as pd
>>> x = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=float)
>>> y = pd.Series([2, 4, 6, 8, 10, 12, 14, 16, 18, 20], dtype=float)
>>> correlation(x, y, period=5)
beta(data, benchmark, period=60)[source]

Rolling beta (OLS slope of data returns vs benchmark returns).

Interpretation:
  • Beta = 1: Asset moves in line with the benchmark.

  • Beta > 1: Asset is more volatile than the benchmark (amplifies market moves). E.g. beta = 1.5 means the stock moves 1.5% for every 1% benchmark move.

  • Beta < 1: Asset is less volatile than the benchmark.

  • Beta < 0: Asset moves inversely to the benchmark (rare).

  • Rising beta: Asset becoming more correlated/volatile relative to benchmark.

  • Beta is the cornerstone of CAPM and factor models.

Parameters:
  • data (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • period (int, default: 60) – Rolling window length.

Returns:

Beta values (unbounded).

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> stock = pd.Series(100 + np.cumsum(np.random.randn(100)))
>>> market = pd.Series(100 + np.cumsum(np.random.randn(100)))
>>> beta(stock, market, period=30)
r_squared(data, benchmark, period=60)[source]

Rolling R-squared (coefficient of determination).

Computed as the square of the rolling Pearson correlation of returns.

Parameters:
  • data (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • period (int, default: 60) – Rolling window length.

Returns:

R-squared values in [0, 1].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> stock = pd.Series(100 + np.cumsum(np.random.randn(100)))
>>> market = pd.Series(100 + np.cumsum(np.random.randn(100)))
>>> r_squared(stock, market, period=30)
information_coefficient(data, other, period=20)[source]

Rolling information coefficient (Spearman rank correlation).

Measures the rolling rank correlation between two series, commonly used to evaluate forecast skill.

Parameters:
  • data (Series) – Forecast or signal series.

  • other (Series) – Realised outcome series.

  • period (int, default: 20) – Rolling window length.

Returns:

IC values in [-1, 1].

Return type:

Series

Example

>>> import pandas as pd
>>> forecast = pd.Series([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=float)
>>> actual = pd.Series([2, 1, 4, 3, 6, 5, 8, 7, 10, 9], dtype=float)
>>> information_coefficient(forecast, actual, period=5)

Cycles

Hilbert Transform, sine wave indicators, bandpass and roofing filters.

Cycle analysis indicators.

This module provides indicators based on digital signal processing techniques, primarily those developed by John Ehlers. They detect dominant cycle periods and separate trend from cycle components. All functions accept pd.Series inputs and return pd.Series (or dict[str, pd.Series] for multi-output indicators).

hilbert_transform_dominant_period(data, min_period=6, max_period=50)[source]

Dominant cycle period via Hilbert Transform.

Uses Ehlers’ Hilbert Transform Discriminator to estimate the dominant cycle period of the price series.

Interpretation:
  • Output is the estimated cycle length in bars (e.g. 20 means the dominant cycle repeats every 20 bars).

  • Use this to adaptively set indicator periods: instead of a fixed 14-period RSI, use the dominant period.

  • Short period (< 10): Fast cycling market.

  • Long period (> 30): Slow cycling or trending market.

  • Stable readings = well-defined cycle. Erratic readings = no clear cycle (trending or random).

Parameters:
  • data (Series) – Price series (typically close).

  • min_period (int, default: 6) – Minimum allowed cycle period.

  • max_period (int, default: 50) – Maximum allowed cycle period.

Returns:

Estimated dominant cycle period in bars.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> hilbert_transform_dominant_period(close)
hilbert_transform_trend_mode(data)[source]

Trend vs cycle mode indicator via Hilbert Transform.

Returns +1 when the market is in trend mode and 0 when in cycle mode, based on the relationship between the dominant cycle period and a simple moving average smoothing window.

Parameters:

data (Series) – Price series.

Returns:

Binary series: 1 = trending, 0 = cycling.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> hilbert_transform_trend_mode(close)
hilbert_instantaneous_phase(data)[source]

Instantaneous trendline via Hilbert Transform.

Computes a smooth trendline by applying the dominant cycle period as an adaptive moving average length.

Parameters:

data (Series) – Price series.

Returns:

Instantaneous trendline values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> hilbert_instantaneous_phase(close)
sine_wave(data)[source]

Ehlers Sine Wave indicator.

Uses the dominant cycle period to compute the sine and lead-sine values, generating buy/sell signals on crossovers.

Interpretation:
  • Sine crosses above lead_sine: Buy signal (cycle turning up).

  • Sine crosses below lead_sine: Sell signal (cycle turning down).

  • When both values are near +/-1, the market is in cycle mode.

  • When values are erratic or near zero, the market may be trending rather than cycling.

Parameters:

data (Series) – Price series.

Returns:

sine and lead_sine series.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> result = sine_wave(close)
even_better_sinewave(data, hp_period=40, ss_period=10)[source]

Ehlers Even Better Sinewave (EBSW).

Combines a high-pass filter, super-smoother, and autocorrelation to produce an oscillator that identifies the dominant cycle.

Interpretation:
  • Near +1: Cycle is at or near a peak.

  • Near -1: Cycle is at or near a trough.

  • Zero crossover up: Cycle turning bullish.

  • Zero crossover down: Cycle turning bearish.

  • More reliable than the original Sine Wave indicator because it better separates cycle from trend components.

Parameters:
  • data (Series) – Price series.

  • hp_period (int, default: 40) – High-pass filter period.

  • ss_period (int, default: 10) – Super-smoother period.

Returns:

EBSW oscillator values in approximately [-1, 1].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> even_better_sinewave(close)
roofing_filter(data, hp_period=48, lp_period=10)[source]

Ehlers Roofing Filter.

Applies a high-pass filter followed by a super-smoother low-pass filter to isolate the dominant cycle from both trend and noise.

Interpretation:
  • Output oscillates around zero, showing the pure cycle component of price.

  • Positive: Cycle is in the up phase.

  • Negative: Cycle is in the down phase.

  • Use to identify cycle turning points without trend or noise contamination.

Parameters:
  • data (Series) – Price series.

  • hp_period (int, default: 48) – High-pass filter cutoff period.

  • lp_period (int, default: 10) – Low-pass (super-smoother) cutoff period.

Returns:

Filtered cycle component.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> roofing_filter(close)
decycler(data, hp_period=125)[source]

Ehlers Decycler.

Removes the cycle component from the price series, keeping only the trend. Computed as price - highpass(price).

Interpretation:
  • Shows the pure trend component of price with cycles removed.

  • Price above decycler: Bullish trend.

  • Price below decycler: Bearish trend.

  • Extremely smooth with virtually no lag – one of the best trend-following overlays available.

Parameters:
  • data (Series) – Price series.

  • hp_period (int, default: 125) – High-pass filter cutoff period. Components with period shorter than this are removed (cycles).

Returns:

Trend-only (decycled) series.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> decycler(close)
bandpass_filter(data, period=20, bandwidth=0.3)[source]

Ehlers Bandpass Filter.

Isolates the cycle component at the specified period. Returns both the bandpass filter output and a trigger signal (one-bar lag).

Interpretation:
  • BP crosses above trigger: Buy signal (cycle turning up).

  • BP crosses below trigger: Sell signal (cycle turning down).

  • BP at peak: Cycle high – potential sell zone.

  • BP at trough: Cycle low – potential buy zone.

  • Only isolates the cycle at the specified period; other frequencies are filtered out.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Centre period of the bandpass.

  • bandwidth (float, default: 0.3) – Bandwidth as a fraction of the centre frequency.

Returns:

bp (bandpass) and trigger (one-bar lag of bp).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(np.sin(np.linspace(0, 8 * np.pi, 200)) * 10 + 100)
>>> result = bandpass_filter(close, period=20)

Custom Indicators

Squeeze Momentum, Anchored VWAP, Adaptive RSI, Linear Regression Channel, Market Structure, Volume-Weighted MACD.

Modern and advanced technical analysis indicators.

This module provides contemporary indicators including squeeze detection, anchored VWAP, market structure analysis, and adaptive oscillators. All functions accept pd.Series inputs and return pd.Series (or dict[str, pd.Series] for multi-output indicators).

squeeze_momentum(high, low, close, bb_period=20, bb_std=2.0, kc_period=20, kc_mult=1.5, mom_period=12)[source]

TTM Squeeze Momentum indicator.

Detects when Bollinger Bands are inside Keltner Channels (the “squeeze”) and measures momentum via a linear regression of price.

Interpretation:
  • squeeze_on = 1: Bollinger Bands are inside Keltner Channels. Volatility is compressed. A breakout is imminent.

  • squeeze_on = 0: No squeeze. Normal volatility.

  • Momentum positive: Bullish momentum – breakout likely up.

  • Momentum negative: Bearish momentum – breakout likely down.

  • Momentum growing: Accelerating.

  • Momentum shrinking: Decelerating.

Trading rules:
  • When squeeze fires (transitions from on to off), enter in the direction of momentum.

  • Exit when momentum starts to decelerate (histogram shrinks).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • bb_period (int, default: 20) – Bollinger Bands SMA period.

  • bb_std (float, default: 2.0) – Bollinger Bands standard deviation multiplier.

  • kc_period (int, default: 20) – Keltner Channel EMA period.

  • kc_mult (float, default: 1.5) – Keltner Channel ATR multiplier.

  • mom_period (int, default: 12) – Momentum linear regression period.

Returns:

squeeze_on (bool: 1 = squeeze active), momentum (momentum histogram values).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> n = 100
>>> c = pd.Series(100 + np.cumsum(np.random.randn(n) * 0.5))
>>> h = c + abs(np.random.randn(n) * 0.3)
>>> lo = c - abs(np.random.randn(n) * 0.3)
>>> result = squeeze_momentum(h, lo, c)
anchored_vwap(close, volume, anchor_index=0)[source]

VWAP anchored from a specific bar index.

Computes the Volume Weighted Average Price starting from anchor_index onwards. Values before the anchor are NaN.

Parameters:
  • close (Series) – Close (or typical) prices.

  • volume (Series) – Volume series.

  • anchor_index (int, default: 0) – The integer position index to begin the VWAP calculation from.

Returns:

Anchored VWAP values.

Return type:

Series

Example

>>> import pandas as pd
>>> close = pd.Series([10, 11, 12, 11, 10, 9, 10, 11, 12, 13], dtype=float)
>>> volume = pd.Series([100, 200, 150, 300, 250, 100, 200, 150, 300, 250], dtype=float)
>>> anchored_vwap(close, volume, anchor_index=3)
linear_regression_channel(data, period=100, std_dev=2.0)[source]

Linear regression channel with standard deviation bands.

Fits a rolling linear regression and constructs upper/lower channel lines based on the standard error.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 100) – Rolling window length for the regression.

  • std_dev (float, default: 2.0) – Number of standard deviations for the channel width.

Returns:

middle (regression value), upper, lower.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(120, dtype=float) * 0.5)
>>> result = linear_regression_channel(close, period=50)
pivot_points(high, low, close, method='standard')[source]

Pivot points with support and resistance levels.

Computes pivot point and two levels of support/resistance using the prior bar’s high, low, and close.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • method (str, default: 'standard') – Calculation method: "standard", "fibonacci", or "woodie".

Returns:

pivot, s1, s2, r1, r2.

Return type:

dict[str, Series]

Example

>>> import pandas as pd
>>> h = pd.Series([12, 13, 14, 13, 12], dtype=float)
>>> lo = pd.Series([10, 11, 12, 11, 10], dtype=float)
>>> c = pd.Series([11, 12, 13, 12, 11], dtype=float)
>>> result = pivot_points(h, lo, c)
market_structure(high, low, lookback=5)[source]

Higher highs / lower lows market structure detection.

Identifies swing highs and lows using a lookback window, then labels each swing as higher-high (HH), lower-high (LH), higher-low (HL), or lower-low (LL).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • lookback (int, default: 5) – Number of bars on each side to confirm a swing point.

Returns:

swing_high (high values at swing highs, else NaN), swing_low (low values at swing lows, else NaN), structure (1 = bullish / HH+HL, -1 = bearish / LH+LL, 0 = neutral).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(50) * 0.5) + 1)
>>> lo = h - 2
>>> result = market_structure(h, lo, lookback=3)
swing_points(high, low, lookback=5)[source]

Swing high and low detection.

A swing high occurs when the high is the maximum of 2 * lookback + 1 bars centred on the pivot bar. Symmetrically for swing lows.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • lookback (int, default: 5) – Number of bars on each side of the pivot.

Returns:

swing_high (high values at swing highs, else NaN), swing_low (low values at swing lows, else NaN).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(50) * 0.5) + 1)
>>> lo = h - 2
>>> result = swing_points(h, lo, lookback=3)
volume_weighted_macd(close, volume, fast=12, slow=26, signal=9)[source]

MACD weighted by volume.

Uses volume-weighted moving averages instead of standard EMAs for the fast and slow lines.

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume series.

  • fast (int, default: 12) – Fast VWMA period.

  • slow (int, default: 26) – Slow VWMA period.

  • signal (int, default: 9) – Signal EMA period.

Returns:

macd, signal, histogram.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> c = pd.Series(100 + np.cumsum(np.random.randn(100) * 0.5))
>>> v = pd.Series(np.random.randint(1000, 10000, 100), dtype=float)
>>> result = volume_weighted_macd(c, v)
ehlers_fisher(high, low, period=10)[source]

Ehlers Fisher Transform.

Converts prices into a Gaussian normal distribution to create sharp turning points, making it easier to identify reversals.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 10) – Look-back period for the normalisation.

Returns:

fisher and trigger (one-bar lag of fisher).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(100) * 0.5) + 1)
>>> lo = h - 2
>>> result = ehlers_fisher(h, lo)
adaptive_rsi(data, base_period=14, vol_period=10, min_period=5, max_period=50)[source]

RSI with an adaptive period based on volatility.

The look-back period expands in low-volatility regimes and contracts in high-volatility regimes, improving responsiveness.

Parameters:
  • data (Series) – Price series (typically close).

  • base_period (int, default: 14) – Base RSI period.

  • vol_period (int, default: 10) – Period for the volatility (standard deviation) calculation.

  • min_period (int, default: 5) – Minimum allowed RSI period.

  • max_period (int, default: 50) – Maximum allowed RSI period.

Returns:

Adaptive RSI values in [0, 100].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> close = pd.Series(100 + np.cumsum(np.random.randn(200) * 0.5))
>>> adaptive_rsi(close)
relative_strength(data, benchmark)[source]

Relative strength ratio of one series to another.

Commonly used for pair analysis or sector rotation. A rising ratio indicates data is outperforming benchmark.

Parameters:
  • data (Series) – Numerator price series (e.g., individual stock).

  • benchmark (Series) – Denominator price series (e.g., index or sector ETF).

Returns:

Ratio of data / benchmark.

Return type:

Series

Example

>>> import pandas as pd
>>> stock = pd.Series([100, 105, 110, 108, 112], dtype=float)
>>> index = pd.Series([1000, 1010, 1005, 1015, 1020], dtype=float)
>>> relative_strength(stock, index)
linear_regression_forecast(data, period=20, forecast_bars=1)[source]

Rolling linear regression forecast N bars ahead.

Fits a linear regression over each rolling window and projects the value forecast_bars steps beyond the last observation in the window.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Rolling window length for the regression.

  • forecast_bars (int, default: 1) – Number of bars ahead to forecast.

Returns:

Forecasted values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) * 0.5)
>>> linear_regression_forecast(close, period=20, forecast_bars=1)
standard_error_bands(data, period=20, num_bands=3)[source]

Linear regression line with standard error bands.

Fits a rolling linear regression and constructs bands at +-1, +-2, and +-3 standard errors (configurable via num_bands).

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Rolling window length.

  • num_bands (int, default: 3) – Number of band levels (1, 2, … num_bands standard errors).

Returns:

middle plus upper_N and lower_N for each band level N from 1 to num_bands.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) * 0.5)
>>> result = standard_error_bands(close, period=20)
r_squared_indicator(data, period=14)[source]

Rolling R-squared of linear regression as a trend strength measure.

An R-squared near 1.0 indicates prices are moving in a strong linear trend; near 0.0 indicates choppy, non-trending movement.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – Rolling window length for the regression.

Returns:

R-squared values in [0, 1].

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) * 0.5)
>>> r_squared_indicator(close, period=14)
polynomial_regression(data, period=20, degree=2)[source]

Rolling polynomial regression fitted values.

Fits a polynomial of the given degree over each rolling window and returns the fitted value at the end of the window.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Rolling window length.

  • degree (int, default: 2) – Polynomial degree (2 = quadratic, 3 = cubic).

Returns:

Fitted polynomial values at the end of each window.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) ** 1.5 * 0.01)
>>> polynomial_regression(close, period=20, degree=2)
raff_regression_channel(data, period=50)[source]

Raff regression channel using maximum deviation.

Fits a rolling linear regression and constructs channel lines using the maximum absolute deviation of any point in the window from the regression line.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 50) – Rolling window length.

Returns:

center (regression line), upper, lower.

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(80, dtype=float) * 0.5)
>>> result = raff_regression_channel(close, period=50)
detrended_regression(data, period=20)[source]

Residuals from rolling linear regression (for mean reversion).

Fits a rolling linear regression and returns the residual (actual minus predicted) at the end of each window. Positive values indicate price above trend; negative below trend.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 20) – Rolling window length.

Returns:

Detrended (residual) values.

Return type:

Series

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series(100 + np.arange(50, dtype=float) * 0.5)
>>> detrended_regression(close, period=20)

Fibonacci

Retracements, extensions, fans, time zones, pivot points, auto-Fibonacci.

Fibonacci-based technical analysis indicators.

This module provides Fibonacci retracement, extension, fan, time zone, pivot point, and auto-detection indicators. All functions accept pd.Series inputs and return dict or list outputs.

fibonacci_retracements(swing_high, swing_low, direction='up')[source]

Compute Fibonacci retracement levels from a swing high/low pair.

Given a swing high and swing low, computes the standard Fibonacci retracement levels at 23.6%, 38.2%, 50%, 61.8%, and 78.6%.

Interpretation:
  • 23.6%: Shallow retracement – strong trend continuation likely. Common in fast-moving markets.

  • 38.2%: Moderate retracement – healthy pullback in a strong trend.

  • 50%: Not a Fibonacci ratio but widely watched. A 50% retracement is considered normal.

  • 61.8%: The “golden ratio” – the most important level. If price holds here, the trend is likely to resume.

  • 78.6%: Deep retracement – the trend is under pressure. If this level breaks, the trend may be over.

Trading rules:
  • Look for buy signals (candlestick patterns, divergence) at 38.2%-61.8% retracement levels in an uptrend.

  • Place stops below the 78.6% level.

  • The stronger the trend, the shallower the retracement (23.6%-38.2%).

Parameters:
  • swing_high (float) – The swing high price.

  • swing_low (float) – The swing low price.

  • direction (str, default: 'up') – If "up", retracements are measured from the high downward (pullback in an uptrend). If "down", retracements are measured from the low upward (pullback in a downtrend).

Returns:

Level names (e.g. "23.6%") as keys and price values.

Return type:

dict[str, float]

Example

>>> result = fibonacci_retracements(swing_high=110.0, swing_low=100.0)
>>> result["50.0%"]
105.0
fibonacci_extensions(swing_low, swing_high, pullback_low)[source]

Compute Fibonacci extension levels from three price points.

Uses a swing low, swing high, and pullback low to project extension levels at 100%, 127.2%, 161.8%, 200%, and 261.8%.

Interpretation:
  • Extension levels project where price might go AFTER a retracement completes.

  • 100%: The most common initial target (move equals the first swing).

  • 127.2%: Common target for corrective waves.

  • 161.8%: The golden extension – a key profit target.

  • 200% and 261.8%: Extended targets for strong trends.

  • Use for setting profit targets and identifying potential resistance levels in a trend.

Parameters:
  • swing_low (float) – The initial swing low price.

  • swing_high (float) – The swing high price.

  • pullback_low (float) – The pullback low price (retracement point).

Returns:

Extension level names as keys and projected price values.

Return type:

dict[str, float]

Example

>>> result = fibonacci_extensions(100.0, 110.0, 105.0)
>>> result["100.0%"]
115.0
fibonacci_fans(pivot_x, pivot_y, target_x, target_y)[source]

Compute Fibonacci fan line slopes from two pivot points.

Draws fan lines from (pivot_x, pivot_y) through Fibonacci retracement levels of the vertical distance to (target_x, target_y).

Parameters:
  • pivot_x (int) – Bar index of the pivot (start) point.

  • pivot_y (float) – Price at the pivot point.

  • target_x (int) – Bar index of the target (end) point.

  • target_y (float) – Price at the target point.

Returns:

Fan line labels as keys and slope values.

Return type:

dict[str, float]

Example

>>> result = fibonacci_fans(0, 100.0, 10, 110.0)
>>> abs(result["50.0%"] - 0.5) < 1e-10
True
fibonacci_time_zones(start_index, max_index)[source]

Compute Fibonacci time zone indices from a start bar.

Generates a sequence of bar indices at Fibonacci intervals (1, 1, 2, 3, 5, 8, 13, 21, …) from the given start index, up to max_index.

Parameters:
  • start_index (int) – The bar index to begin the Fibonacci time zones from.

  • max_index (int) – The maximum bar index (exclusive) to generate zones up to.

Returns:

List of bar indices at Fibonacci time intervals.

Return type:

list[int]

Example

>>> fibonacci_time_zones(0, 50)
[1, 2, 3, 5, 8, 13, 21, 34]
fibonacci_pivot_points(high, low, close)[source]

Pivot points using Fibonacci ratios.

Computes the standard pivot P = (H + L + C) / 3 and derives support/resistance using Fibonacci ratios applied to the prior bar’s range.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

Returns:

pivot, s1, s2, s3, r1, r2, r3.

Return type:

dict[str, Series]

Example

>>> import pandas as pd
>>> h = pd.Series([12, 13, 14, 13, 12], dtype=float)
>>> lo = pd.Series([10, 11, 12, 11, 10], dtype=float)
>>> c = pd.Series([11, 12, 13, 12, 11], dtype=float)
>>> result = fibonacci_pivot_points(h, lo, c)
auto_fibonacci(data, lookback=50, direction='up')[source]

Automatically detect swing high/low and compute Fibonacci retracements.

Scans the most recent lookback bars to find the highest high and lowest low, then computes Fibonacci retracement levels.

Parameters:
  • data (Series) – Price series (typically close).

  • lookback (int, default: 50) – Number of recent bars to scan for swing points.

  • direction (str, default: 'up') – Trend direction assumption: "up" retraces from high downward, "down" retraces from low upward.

Returns:

swing_high (float), swing_high_idx (index label), swing_low (float), swing_low_idx (index label), levels (dict of retracement levels).

Return type:

dict[str, object]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> close = pd.Series(100 + np.cumsum(np.random.randn(100) * 0.5))
>>> result = auto_fibonacci(close, lookback=30)

Support & Resistance

Algorithmic detection of support/resistance levels, fractal levels, supply/demand zones, trendlines.

Support and resistance detection indicators.

This module provides tools for identifying horizontal support/resistance levels, fractals, supply/demand zones, and trendlines from price data. All functions accept pd.Series inputs and return dict, list, or pd.Series outputs.

find_support_resistance(high, low, lookback=5, num_levels=5, tolerance=0.02)[source]

Detect horizontal support and resistance levels via clustering.

Identifies local swing highs and swing lows, then clusters nearby levels within tolerance (as a fraction of price) to produce consolidated S/R levels.

Interpretation:
  • Support levels: Prices where buying pressure historically prevented further decline. Price tends to bounce at these levels.

  • Resistance levels: Prices where selling pressure historically prevented further advance.

  • Multiple touches: A level tested many times is stronger.

  • Breakout through resistance: Resistance becomes support (role reversal) and vice versa.

Trading rules:
  • Buy at support levels with confirmation (candlestick pattern, volume spike).

  • Sell at resistance levels with confirmation.

  • Place stops on the other side of the S/R level.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • lookback (int, default: 5) – Number of bars on each side to confirm a swing point.

  • num_levels (int, default: 5) – Maximum number of S/R levels to return per side.

  • tolerance (float, default: 0.02) – Fraction of price within which nearby levels are merged.

Returns:

support and resistance lists of price levels, sorted ascending.

Return type:

dict[str, list[float]]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(200) * 0.5) + 1)
>>> lo = h - 2
>>> result = find_support_resistance(h, lo)
price_clustering(data, num_levels=5, bins=100)[source]

Find price levels where price has spent the most time.

Builds a histogram of price values and returns the bin centres with the highest counts, analogous to a simplified volume profile.

Parameters:
  • data (Series) – Price series (typically close).

  • num_levels (int, default: 5) – Number of key price levels to return.

  • bins (int, default: 100) – Number of histogram bins.

Returns:

Array of key price levels sorted ascending.

Return type:

ndarray

Example

>>> import pandas as pd, numpy as np
>>> close = pd.Series([100, 101, 100, 99, 100, 101, 102, 100], dtype=float)
>>> price_clustering(close, num_levels=3)
fractal_levels(high, low, period=2)[source]

Williams fractal swing high/low identification.

An up-fractal occurs when the high is the highest of 2 * period + 1 bars. A down-fractal occurs when the low is the lowest.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 2) – Number of bars on each side of the fractal pivot.

Returns:

up_fractals (boolean Series, True at up-fractal bars), down_fractals (boolean Series, True at down-fractal bars).

Return type:

dict[str, Series]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(50) * 0.5) + 1)
>>> lo = h - 2
>>> result = fractal_levels(h, lo, period=2)
round_number_levels(current_price, num_levels=5, step=None)[source]

Generate psychological round number levels near the current price.

Computes evenly spaced round numbers above and below the given price. Useful for identifying potential support/resistance at psychologically significant prices.

Parameters:
  • current_price (float) – The current (or reference) price.

  • num_levels (int, default: 5) – Number of levels to return on each side (above and below).

  • step (float | None, default: None) – Step size between levels. If None, automatically determined from the magnitude of current_price.

Returns:

Sorted list of round number price levels.

Return type:

list[float]

Example

>>> round_number_levels(105.3, num_levels=3, step=10.0)
[80.0, 90.0, 100.0, 110.0, 120.0, 130.0]
supply_demand_zones(open_, high, low, close, body_pct=0.6, consolidation_bars=3)[source]

Detect supply and demand zones from price action.

A demand zone forms when a large bullish candle follows a period of basing (small bodies). A supply zone forms similarly for bearish moves. Zones are defined by the basing candles’ range.

Parameters:
  • open (pd.Series) – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • body_pct (float, default: 0.6) – Minimum body-to-range ratio to qualify as a “large” candle.

  • consolidation_bars (int, default: 3) – Number of preceding small-body bars required for basing.

  • open_ (Series)

Returns:

demand and supply lists, each containing dicts with zone_low, zone_high, and index keys.

Return type:

dict[str, list[dict[str, float]]]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> n = 100
>>> c = pd.Series(100 + np.cumsum(np.random.randn(n) * 0.5))
>>> o = c.shift(1).fillna(c.iloc[0])
>>> h = pd.concat([o, c], axis=1).max(axis=1) + 0.5
>>> lo = pd.concat([o, c], axis=1).min(axis=1) - 0.5
>>> result = supply_demand_zones(o, h, lo, c)
Parameters:
Return type:

dict[str, list[dict[str, float]]]

trendline_detection(high, low, lookback=5, min_touches=2)[source]

Fit linear trendlines to swing high and swing low points.

Detects swing points, then fits lines through the most recent swing highs (resistance trendline) and swing lows (support trendline) using least-squares regression.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • lookback (int, default: 5) – Number of bars on each side for swing point detection.

  • min_touches (int, default: 2) – Minimum number of swing points required to fit a trendline.

Returns:

resistance_lines and support_lines, each containing dicts with slope, intercept, and num_touches keys.

Return type:

dict[str, list[dict[str, float]]]

Example

>>> import pandas as pd, numpy as np
>>> np.random.seed(42)
>>> h = pd.Series(100 + np.cumsum(np.random.randn(100) * 0.5) + 1)
>>> lo = h - 2
>>> result = trendline_detection(h, lo, lookback=5)

Market Breadth

Advance/Decline, McClellan, Arms Index, percent above MA – for indices and baskets.

Market breadth indicators.

This module provides indicators that measure the overall health and direction of the broader market by analyzing the number of advancing/declining issues, new highs/lows, and the percentage of components meeting certain criteria. All functions accept pd.Series (or pd.DataFrame where noted) inputs and return pd.Series.

advance_decline_line(advancing, declining)[source]

Advance/Decline Line – cumulative sum of (advancing - declining).

The A/D line is a breadth indicator that tracks the running total of the difference between the number of advancing and declining issues.

Interpretation:
  • Rising A/D line with rising market: Healthy uptrend – broad participation confirms the rally.

  • Falling A/D line with rising market: Bearish divergence – fewer stocks participating in the rally. Distribution.

  • Rising A/D line with falling market: Bullish divergence – accumulation occurring beneath the surface.

  • The A/D line often leads the market at major turning points.

Parameters:
  • advancing (Series) – Number of advancing issues per period.

  • declining (Series) – Number of declining issues per period.

Returns:

Cumulative A/D line values.

Return type:

Series

Example

>>> adv = pd.Series([200, 250, 180, 300, 220])
>>> dec = pd.Series([100, 150, 220, 100, 180])
>>> advance_decline_line(adv, dec)
advance_decline_ratio(advancing, declining)[source]

Advance/Decline Ratio — advancing / declining.

Values above 1.0 indicate more advancers than decliners; below 1.0 indicates more decliners.

Parameters:
  • advancing (Series) – Number of advancing issues per period.

  • declining (Series) – Number of declining issues per period.

Returns:

A/D ratio values (NaN where declining is zero).

Return type:

Series

Example

>>> adv = pd.Series([200, 250, 180])
>>> dec = pd.Series([100, 150, 220])
>>> advance_decline_ratio(adv, dec)
mcclellan_oscillator(advancing, declining, fast=19, slow=39)[source]

McClellan Oscillator – difference between fast and slow EMA of AD diff.

McClellan = EMA(advancing - declining, fast) - EMA(advancing - declining, slow)

Interpretation:
  • Above zero: Short-term breadth momentum is positive (more stocks advancing than declining, accelerating).

  • Below zero: Short-term breadth momentum is negative.

  • Above +100: Very overbought breadth-wise.

  • Below -100: Very oversold breadth-wise.

  • Zero-line crossover: Breadth momentum shift.

  • Best used for timing entries: buy when the oscillator turns up from below -100 (oversold breadth bounce).

Parameters:
  • advancing (Series) – Number of advancing issues per period.

  • declining (Series) – Number of declining issues per period.

  • fast (int, default: 19) – Fast EMA period.

  • slow (int, default: 39) – Slow EMA period.

Returns:

McClellan Oscillator values.

Return type:

Series

Example

>>> result = mcclellan_oscillator(advancing, declining)
mcclellan_summation(advancing, declining, fast=19, slow=39)[source]

McClellan Summation Index – cumulative sum of the McClellan Oscillator.

This is the running total of the McClellan Oscillator, providing a longer-term view of market breadth.

Interpretation:
  • Rising: Long-term breadth is improving (more and more stocks participating in the advance).

  • Falling: Long-term breadth is deteriorating.

  • Above +1000: Strongly bullish long-term breadth.

  • Below -1000: Strongly bearish long-term breadth.

  • Acts as a long-term trend indicator for market internals.

Parameters:
  • advancing (Series) – Number of advancing issues per period.

  • declining (Series) – Number of declining issues per period.

  • fast (int, default: 19) – Fast EMA period for the underlying oscillator.

  • slow (int, default: 39) – Slow EMA period for the underlying oscillator.

Returns:

McClellan Summation Index values.

Return type:

Series

Example

>>> result = mcclellan_summation(advancing, declining)
arms_index(advancing_issues, declining_issues, advancing_volume, declining_volume)[source]

Arms Index (TRIN) — Short-Term Trading Index.

``TRIN = (Advancing Issues / Declining Issues) /

(Advancing Volume / Declining Volume)``

Values below 1.0 are bullish (more volume flowing into advancers); values above 1.0 are bearish.

Parameters:
  • advancing_issues (Series) – Number of advancing issues.

  • declining_issues (Series) – Number of declining issues.

  • advancing_volume (Series) – Total volume of advancing issues.

  • declining_volume (Series) – Total volume of declining issues.

Returns:

TRIN values (NaN where denominators are zero).

Return type:

Series

Example

>>> result = arms_index(adv_issues, dec_issues, adv_vol, dec_vol)
new_highs_lows(new_highs, new_lows)[source]

New Highs minus New Lows.

A simple breadth measure: positive values indicate more new highs than new lows, suggesting bullish breadth.

Parameters:
  • new_highs (Series) – Number of new highs per period.

  • new_lows (Series) – Number of new lows per period.

Returns:

New highs minus new lows.

Return type:

Series

Example

>>> nh = pd.Series([50, 60, 30])
>>> nl = pd.Series([20, 40, 50])
>>> new_highs_lows(nh, nl)
percent_above_ma(prices_df, period=50)[source]

Percentage of components above their N-period moving average.

For each row, computes how many columns have a value above their respective rolling SMA, expressed as a percentage.

Parameters:
  • prices_df (DataFrame) – DataFrame where each column is a component’s price series.

  • period (int, default: 50) – SMA look-back period.

Returns:

Percentage (0-100) of components above their SMA.

Return type:

Series

Example

>>> df = pd.DataFrame({"A": [10, 11, 12], "B": [20, 19, 18]})
>>> percent_above_ma(df, period=2)
high_low_index(new_highs, new_lows)[source]

High-Low Index — new highs as a percentage of new highs + new lows.

HLI = new_highs / (new_highs + new_lows) * 100

Values above 50 indicate more new highs; values below 50 indicate more new lows.

Parameters:
  • new_highs (Series) – Number of new highs per period.

  • new_lows (Series) – Number of new lows per period.

Returns:

High-Low Index values in [0, 100] (NaN where both are zero).

Return type:

Series

Example

>>> nh = pd.Series([50, 60, 30])
>>> nl = pd.Series([20, 40, 50])
>>> high_low_index(nh, nl)
bullish_percent(prices_df, period=50)[source]

Bullish Percent Index (simplified).

Approximates the Bullish Percent Index by computing the percentage of components trading above their period-day simple moving average. The traditional BPI uses point-and-figure buy signals, but the SMA crossover is a widely accepted simplification.

Parameters:
  • prices_df (DataFrame) – DataFrame where each column is a component’s price series.

  • period (int, default: 50) – SMA look-back period (default 50-day MA).

Returns:

Bullish Percent values in [0, 100].

Return type:

Series

Example

>>> df = pd.DataFrame({"A": [10, 11, 12], "B": [20, 19, 18]})
>>> bullish_percent(df, period=2)
cumulative_volume_index(close, volume)[source]

Cumulative Volume Index (CVI).

Adds volume on up days and subtracts volume on down days.

CVI = cumsum(sign(close.diff()) * volume)

Parameters:
  • close (Series) – Close prices.

  • volume (Series) – Volume data.

Returns:

CVI values.

Return type:

Series

Example

>>> close = pd.Series([100, 102, 101, 103, 104.0])
>>> volume = pd.Series([1000, 1500, 1200, 1800, 1600.0])
>>> cumulative_volume_index(close, volume)

Performance

Relative performance, alpha, tracking error, up/down capture, drawdown analytics.

Performance and comparison indicators.

This module provides indicators that measure asset performance relative to a benchmark or on an absolute basis: relative strength, alpha, tracking error, drawdowns, and risk-adjusted return metrics. All functions accept pd.Series inputs and return pd.Series (or dict where noted).

relative_performance(asset, benchmark)[source]

Relative Performance – ratio of asset to benchmark, normalized to 100.

RP = (asset / benchmark) / (asset.iloc[0] / benchmark.iloc[0]) * 100

Interpretation:
  • Rising line: Asset is outperforming the benchmark. Buy the asset, sell the benchmark (or use as a selection filter).

  • Falling line: Asset is underperforming the benchmark.

  • Above 100: Asset has outperformed since the start of the measurement period.

  • Below 100: Asset has underperformed.

  • Use to identify sector rotation and relative strength leaders.

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

Returns:

Relative performance, starting at 100.

Return type:

Series

Example

>>> asset = pd.Series([100, 105, 110])
>>> bench = pd.Series([100, 102, 104])
>>> relative_performance(asset, bench)
mansfield_rsi(asset, benchmark, period=52)[source]

Mansfield Relative Strength (not Wilder RSI).

Compares the asset/benchmark ratio to its own simple moving average, expressing the result as a percentage deviation.

MRS = ((asset / benchmark) / SMA(asset / benchmark, period) - 1) * 100

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • period (int, default: 52) – SMA look-back period.

Returns:

Mansfield RS values (percentage above/below zero line).

Return type:

Series

Example

>>> result = mansfield_rsi(asset, benchmark, period=52)
alpha(asset, benchmark, window=60, risk_free=0.0)[source]

Rolling Jensen’s Alpha vs. benchmark.

Computes alpha as the intercept of the rolling OLS regression of excess asset returns on excess benchmark returns.

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • window (int, default: 60) – Rolling window size (number of periods).

  • risk_free (float, default: 0.0) – Per-period risk-free rate.

Returns:

Rolling alpha values (annualization depends on input frequency).

Return type:

Series

Example

>>> result = alpha(asset, benchmark, window=60)
tracking_error(asset, benchmark, window=60)[source]

Rolling Tracking Error vs. benchmark.

Tracking error is the standard deviation of the difference in returns between the asset and the benchmark over a rolling window.

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

  • window (int, default: 60) – Rolling window size.

Returns:

Rolling tracking error values.

Return type:

Series

Example

>>> result = tracking_error(asset, benchmark, window=60)
up_down_capture(asset, benchmark)[source]

Up/Down Market Capture Ratio.

Measures how much of the benchmark’s up- and down-market returns the asset captures.

Parameters:
  • asset (Series) – Asset price series.

  • benchmark (Series) – Benchmark price series.

Returns:

up_capture, down_capture, and capture_ratio (up/down).

Return type:

dict[str, float]

Example

>>> result = up_down_capture(asset, benchmark)
>>> result["up_capture"]
drawdown(data)[source]

Drawdown from peak – current decline from running maximum.

DD = (data - running_max) / running_max

Returns non-positive values (0 at peaks, negative during drawdowns).

Interpretation:
  • 0: At or near all-time high (no drawdown).

  • -0.05 to -0.10: Mild pullback (5-10%). Normal in healthy trends.

  • -0.10 to -0.20: Correction territory. May indicate trend weakness.

  • < -0.20: Bear market territory. Significant damage to portfolio.

  • Drawdown duration (how long it stays negative) is often more painful psychologically than drawdown depth.

Parameters:

data (Series) – Price or equity curve.

Returns:

Drawdown values (non-positive fractions).

Return type:

Series

Example

>>> prices = pd.Series([100, 105, 102, 108, 103])
>>> drawdown(prices)
max_drawdown_rolling(data, window=252)[source]

Rolling maximum drawdown over a look-back window.

For each point, computes the worst drawdown experienced within the trailing window periods.

Interpretation:
  • Tracks the worst loss experienced in the recent past.

  • Deepening max drawdown: Risk is increasing.

  • Stable, shallow max drawdown: Low-risk environment.

  • Use as a risk management metric: if rolling max drawdown exceeds a threshold, reduce position size or exit.

Parameters:
  • data (Series) – Price or equity curve.

  • window (int, default: 252) – Rolling look-back window.

Returns:

Rolling max drawdown values (non-positive fractions).

Return type:

Series

Example

>>> result = max_drawdown_rolling(prices, window=60)
pain_index(data, window=252)[source]

Pain Index — mean of absolute drawdowns over a rolling window.

The Pain Index averages the magnitude of drawdowns; a higher value indicates more sustained or deeper drawdowns.

Parameters:
  • data (Series) – Price or equity curve.

  • window (int, default: 252) – Rolling look-back window.

Returns:

Pain Index values (non-negative).

Return type:

Series

Example

>>> result = pain_index(prices, window=60)
gain_loss_ratio(data, window=20)[source]

Gain/Loss Ratio — average gain / average loss over a rolling window.

Uses the per-period returns (percentage change) of the input series. Values above 1.0 indicate larger average gains than average losses.

Parameters:
  • data (Series) – Price series.

  • window (int, default: 20) – Rolling look-back window.

Returns:

Gain/loss ratio values (NaN when no losses or no gains in window).

Return type:

Series

Example

>>> result = gain_loss_ratio(prices, window=20)
profit_factor(data, window=20)[source]

Profit Factor — sum of gains / sum of losses over a rolling window.

Uses the per-period returns (percentage change) of the input series. Values above 1.0 indicate total gains exceed total losses.

Parameters:
  • data (Series) – Price series.

  • window (int, default: 20) – Rolling look-back window.

Returns:

Profit factor values (NaN when no losses in window).

Return type:

Series

Example

>>> result = profit_factor(prices, window=20)

Smoothing

ALMA, JMA, Butterworth, Super Smoother, Gaussian, windowed MAs.

Advanced smoothing and filtering indicators.

This module provides sophisticated moving averages and digital filters used in technical analysis. All functions accept pd.Series inputs and return pd.Series.

alma(data, period=9, offset=0.85, sigma=6.0)[source]

Arnaud Legoux Moving Average (ALMA).

A Gaussian-weighted moving average that allows the user to control the position of the bell curve along the window via offset and the width via sigma.

Interpretation:
  • Price above ALMA: Bullish.

  • Price below ALMA: Bearish.

  • Combines the responsiveness of EMA with the smoothness of Gaussian weighting. The offset parameter lets you place more weight on recent prices (offset near 1) or older prices (offset near 0).

  • Excellent alternative to EMA for crossover systems.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 9) – Window length.

  • offset (float, default: 0.85) – Controls the position of the Gaussian peak within the window. 0 = far left (oldest), 1 = far right (newest).

  • sigma (float, default: 6.0) – Controls the width of the Gaussian bell curve. Higher values produce a broader, smoother curve.

Returns:

ALMA values. The first period - 1 entries are NaN.

Return type:

Series

Example

>>> result = alma(close, period=9, offset=0.85, sigma=6.0)
lsma(data, period=25)[source]

Least Squares Moving Average (LSMA).

Also known as the Linear Regression Value or End Point Moving Average. At each bar, a least-squares line is fit over the window and the endpoint of the line is returned.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 25) – Window length for the linear regression.

Returns:

LSMA values.

Return type:

Series

Example

>>> result = lsma(close, period=25)
swma(data)[source]

Symmetrically Weighted Moving Average (SWMA).

A 4-bar weighted average using weights [1, 2, 2, 1] / 6.

Parameters:

data (Series) – Price series.

Returns:

SWMA values. The first 3 entries are NaN.

Return type:

Series

Example

>>> result = swma(close)
sinema(data, period=14)[source]

Sine-Weighted Moving Average.

Each element in the window is weighted by the sine of its proportional position within a half-period (pi), giving the most weight to the center of the window.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Window length.

Returns:

Sine-weighted moving average values.

Return type:

Series

Example

>>> result = sinema(close, period=14)
trima(data, period=20)[source]

Triangular Moving Average (TRIMA).

Equivalent to a double SMA: SMA(SMA(data, ceil((period+1)/2)), floor((period+1)/2)). This produces a smoother curve than a single SMA by effectively giving the most weight to the center of the window.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 20) – Overall window length.

Returns:

TRIMA values.

Return type:

Series

Example

>>> result = trima(close, period=20)
jma(data, period=7, phase=50.0, power=2)[source]

Jurik Moving Average approximation (JMA).

An adaptive moving average that attempts to minimize lag and overshoot. This is an approximation of the proprietary Jurik algorithm using an adaptive EMA with phase and power controls.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 7) – Smoothing period.

  • phase (float, default: 50.0) – Phase parameter in the range [-100, 100]. Controls the tradeoff between lag and overshoot. 0 is balanced, positive reduces lag.

  • power (int, default: 2) – Power parameter controlling the smoothing curve shape.

Returns:

JMA values.

Return type:

Series

Example

>>> result = jma(close, period=7, phase=50, power=2)
gaussian_filter(data, period=14, poles=2)[source]

Gaussian-weighted rolling filter.

Applies a discrete Gaussian kernel over the rolling window. The standard deviation of the kernel is set to period / 4 so that the window captures approximately two standard deviations.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Window length.

  • poles (int, default: 2) – Number of standard deviations captured within the window. Used to set sigma = period / (2 * poles).

Returns:

Gaussian-filtered values.

Return type:

Series

Example

>>> result = gaussian_filter(close, period=14)
butterworth_filter(data, period=14)[source]

2nd-order Butterworth low-pass filter (IIR).

This implements the classic Ehlers two-pole Butterworth filter, which provides smooth output with minimal lag relative to its degree of smoothing.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Cut-off period in bars.

Returns:

Butterworth-filtered values.

Return type:

Series

Example

>>> result = butterworth_filter(close, period=14)
supersmoother(data, period=14)[source]

Ehlers Super Smoother (2-pole Butterworth variant).

A modified Butterworth filter by John Ehlers that removes aliasing noise while retaining a smooth, low-lag response.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Cut-off period in bars.

Returns:

Super-smoothed values.

Return type:

Series

Example

>>> result = supersmoother(close, period=14)
hann_window_ma(data, period=14)[source]

Hann (raised cosine) windowed moving average.

Each element in the window is weighted by the Hann function: w(i) = 0.5 * (1 - cos(2 * pi * i / (N - 1)))

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Window length.

Returns:

Hann-windowed moving average values.

Return type:

Series

Example

>>> result = hann_window_ma(close, period=14)
hamming_window_ma(data, period=14)[source]

Hamming windowed moving average.

Each element in the window is weighted by the Hamming function: w(i) = 0.54 - 0.46 * cos(2 * pi * i / (N - 1))

Parameters:
  • data (Series) – Price series.

  • period (int, default: 14) – Window length.

Returns:

Hamming-windowed moving average values.

Return type:

Series

Example

>>> result = hamming_window_ma(close, period=14)
kaufman_efficiency_ratio(data, period=10)[source]

Kaufman Efficiency Ratio (ER).

Measures the efficiency of price movement as the ratio of directional change to total path length. This is the core component of the Kaufman Adaptive Moving Average (KAMA).

ER = |close - close[period]| / sum(|close - close[1]|, period)

Values near 1.0 indicate strong trending; values near 0.0 indicate choppy / mean-reverting markets.

Parameters:
  • data (Series) – Price series.

  • period (int, default: 10) – Look-back period.

Returns:

Efficiency ratio values in [0, 1].

Return type:

Series

Example

>>> result = kaufman_efficiency_ratio(close, period=10)

Exotic Indicators

Choppiness Index, Random Walk Index, Polarized Fractal Efficiency, Elder Thermometer, Connors TPS, and more.

Lesser-known and exotic technical analysis indicators.

This module provides uncommon or specialized indicators that measure various aspects of market behaviour. All functions accept pd.Series inputs and return pd.Series (or dict[str, pd.Series] for multi-output indicators).

choppiness_index(high, low, close, period=14)[source]

Choppiness Index.

Measures whether the market is trending or range-bound.

Interpretation:
  • > 61.8: Choppy / range-bound market. Avoid trend-following strategies; use mean-reversion instead.

  • < 38.2: Strong trending market. Use trend-following strategies; avoid mean-reversion.

  • 38.2-61.8: Transitional zone.

  • Does NOT indicate trend direction, only whether a trend exists.

  • Low choppiness often precedes a breakout.

Trading rules:
  • Apply trend strategies when CI < 38.2.

  • Apply range strategies when CI > 61.8.

  • Wait for CI to drop before entering breakout trades.

CI = 100 * log10(sum(ATR(1), n) / (highest_high - lowest_low)) / log10(n)

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

Returns:

Choppiness Index values, typically in [0, 100].

Return type:

Series

Example

>>> result = choppiness_index(high, low, close, period=14)
random_walk_index(high, low, close, period=14)[source]

Random Walk Index (RWI).

Compares the range of directional price moves to the expected range of a random walk. Values above 1.0 suggest trending behavior.

Interpretation:
  • RWI High > 1: Upward price movement exceeds what a random walk would produce = genuine uptrend.

  • RWI Low > 1: Downward price movement exceeds random walk = genuine downtrend.

  • Both < 1: Price movement is consistent with random noise = no trend.

  • RWI High > RWI Low: Bullish bias.

  • RWI Low > RWI High: Bearish bias.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Look-back period.

Returns:

rwi_high and rwi_low.

Return type:

dict[str, Series]

Example

>>> result = random_walk_index(high, low, close, period=14)
>>> result["rwi_high"]
polarized_fractal_efficiency(close, period=10, smoothing=5)[source]

Polarized Fractal Efficiency (PFE).

Measures the efficiency of the price path using fractal geometry. A straight-line move yields +/- 100; a random walk yields ~0.

Interpretation:
  • > 0: Price is moving efficiently upward (trending up).

  • < 0: Price is moving efficiently downward (trending down).

  • Near 0: Choppy, inefficient movement (no trend).

  • > +50: Strong bullish trend.

  • < -50: Strong bearish trend.

  • Think of it as “how direct is the price path” – values near +/-100 mean a straight line, near 0 means a random walk.

PFE = sign(direction) * sqrt(sum_sq_diff + direction^2) / sum_single_diff * 100

The raw PFE is then smoothed with an EMA.

Parameters:
  • close (Series) – Close prices.

  • period (int, default: 10) – Look-back period.

  • smoothing (int, default: 5) – EMA smoothing period applied to the raw PFE.

Returns:

PFE values, bounded roughly in [-100, 100].

Return type:

Series

Example

>>> result = polarized_fractal_efficiency(close, period=10)
price_zone_oscillator(close, period=14)[source]

Price Zone Oscillator (PZO).

An EMA-based oscillator that classifies price action into zones. A positive close change gets +close, negative gets -close.

PZO = 100 * EMA(signed_close, period) / EMA(close, period)

Parameters:
  • close (Series) – Close prices.

  • period (int, default: 14) – EMA period.

Returns:

PZO values, typically in [-100, 100].

Return type:

Series

Example

>>> result = price_zone_oscillator(close, period=14)
ergodic_oscillator(close, fast=5, slow=20, signal=5)[source]

Ergodic Oscillator.

A True Strength Index variant that produces a histogram (oscillator minus signal line) for identifying momentum shifts.

Parameters:
  • close (Series) – Close prices.

  • fast (int, default: 5) – Fast double-smoothing EMA period.

  • slow (int, default: 20) – Slow double-smoothing EMA period.

  • signal (int, default: 5) – Signal line EMA period.

Returns:

ergodic (the TSI line), signal, and histogram.

Return type:

dict[str, Series]

Example

>>> result = ergodic_oscillator(close)
>>> result["ergodic"]
elder_thermometer(high, low, period=22)[source]

Elder Thermometer.

Measures the distance of the current bar from the previous bar’s range, indicating how far price has moved beyond the prior bar.

Thermo = max(high - prev_high, prev_low - low, 0)

The result is smoothed with an EMA.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 22) – EMA smoothing period.

Returns:

Elder Thermometer values (non-negative).

Return type:

Series

Example

>>> result = elder_thermometer(high, low, period=22)
market_facilitation_index(high, low, volume)[source]

Market Facilitation Index (MFI / BW MFI).

Also known as the Bill Williams Market Facilitation Index. Measures the efficiency of price movement per unit of volume.

MFI = (high - low) / volume

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • volume (Series) – Volume data.

Returns:

Market Facilitation Index values.

Return type:

Series

Example

>>> result = market_facilitation_index(high, low, volume)
efficiency_ratio(data, period=10)[source]

Efficiency Ratio (ER).

Measures the efficiency of price movement as the ratio of net directional change to the total path traveled.

ER = |close - close[n]| / sum(|close - close[1]|, n)

Values near 1.0 indicate a strong trend; values near 0.0 indicate choppy, range-bound price action.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 10) – Look-back period.

Returns:

Efficiency ratio values in [0, 1].

Return type:

Series

Example

>>> result = efficiency_ratio(close, period=10)
trend_intensity_index(data, period=30)[source]

Trend Intensity Index (TII).

Measures the percentage of closes above or below the SMA over the look-back period.

TII = 100 * (count_above - count_below) / period

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 30) – Look-back period.

Returns:

TII values in [-100, 100]. Positive indicates bullish bias; negative indicates bearish bias.

Return type:

Series

Example

>>> result = trend_intensity_index(close, period=30)
directional_movement_index(high, low, close, period=14)[source]

Simplified Directional Movement Index (DMI).

Computes +DI and -DI without the full ADX smoothing, providing raw directional movement readings.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – Smoothing period.

Returns:

plus_di (+DI) and minus_di (-DI), both in [0, 100].

Return type:

dict[str, Series]

Example

>>> result = directional_movement_index(high, low, close, period=14)
>>> result["plus_di"]
kairi(data, period=14)[source]

KAIRI — percentage deviation from the SMA.

KAIRI = ((close - SMA(close, period)) / SMA(close, period)) * 100

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – SMA period.

Returns:

KAIRI values (percentage, unbounded).

Return type:

Series

Example

>>> result = kairi(close, period=14)
gopalakrishnan_range(high, low, period=5)[source]

Gopalakrishnan Range Index (GAPO).

GAPO = log(max_high - min_low) / log(period)

Measures the log of the high-low range relative to the log of the look-back period. Higher values indicate larger ranges.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 5) – Look-back period.

Returns:

GAPO values (non-negative).

Return type:

Series

Example

>>> result = gopalakrishnan_range(high, low, period=5)
pretty_good_oscillator(high, low, close, period=14)[source]

Pretty Good Oscillator (PGO).

PGO = (close - SMA(close, period)) / ATR(period)

Normalizes the deviation from the SMA by the ATR, producing a volatility-adjusted momentum reading.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – SMA / ATR period.

Returns:

PGO values (unbounded).

Return type:

Series

Example

>>> result = pretty_good_oscillator(high, low, close, period=14)
connors_tps(data, period=2)[source]

ConnorsRSI TPS component — cumulative streak RSI.

Computes an up/down streak series, then applies RSI to the streak values. This isolates the streak component of ConnorsRSI.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 2) – RSI period applied to the streak series.

Returns:

Streak RSI values in [0, 100].

Return type:

Series

Example

>>> result = connors_tps(close, period=2)
relative_momentum_index(data, period=14, momentum_period=4)[source]

Relative Momentum Index (RMI).

RSI applied to momentum (close - close[momentum_period]) instead of the simple one-bar change. This produces a smoother oscillator that reacts to the direction and magnitude of price swings over momentum_period bars.

Parameters:
  • data (Series) – Price series (typically close).

  • period (int, default: 14) – RSI smoothing period.

  • momentum_period (int, default: 4) – Look-back for the momentum (difference) calculation.

Returns:

RMI values in [0, 100].

Return type:

Series

Example

>>> result = relative_momentum_index(close, period=14, momentum_period=4)

Candlestick Analytics

Structural candlestick measures: body size, shadow ratios, inside/outside bars, pin bars.

Candlestick analytics (structural metrics, not pattern recognition).

Functions in this module quantify the shape of individual candlesticks — body size, shadow ratios, gaps, and structural bar classifications such as inside bars, outside bars, and pin bars. All functions accept pd.Series inputs and return pd.Series.

candle_body_size(open_, close)[source]

Absolute candle body size.

Computed as abs(close - open).

Interpretation:
  • Large body: Strong conviction – one side dominated.

  • Small body: Indecision or low activity.

  • Compare to average body size to identify unusual bars.

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Absolute body size for each bar.

Example

>>> body = candle_body_size(open_, close)
Parameters:
Return type:

Series

candle_range(high, low)[source]

Full candle range (high minus low).

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

Return type:

Series

Returns:

Range for each bar.

Example

>>> rng = candle_range(high, low)
upper_shadow_ratio(open_, high, low, close)[source]

Upper shadow as a fraction of the total candle range.

upper_shadow / (high - low)

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Upper shadow ratio in [0, 1]. Returns 0 when the range is zero.

Example

>>> ratio = upper_shadow_ratio(open_, high, low, close)
Parameters:
Return type:

Series

lower_shadow_ratio(open_, high, low, close)[source]

Lower shadow as a fraction of the total candle range.

lower_shadow / (high - low)

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Lower shadow ratio in [0, 1]. Returns 0 when the range is zero.

Example

>>> ratio = lower_shadow_ratio(open_, high, low, close)
Parameters:
Return type:

Series

body_to_range_ratio(open_, high, low, close)[source]

Body size as a fraction of the total candle range.

abs(close - open) / (high - low)

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Body-to-range ratio in [0, 1]. Returns 0 when the range is zero.

Example

>>> ratio = body_to_range_ratio(open_, high, low, close)
Parameters:
Return type:

Series

candle_direction(open_, close, doji_threshold=0.0)[source]

Candle direction: 1 (bullish), -1 (bearish), 0 (doji).

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • doji_threshold (float, default: 0.0) – Maximum absolute difference between close and open to classify the candle as a doji (default 0.0 — exact equality).

  • open_ (Series)

Return type:

Series

Returns:

Direction for each bar.

Example

>>> direction = candle_direction(open_, close)
Parameters:
Return type:

Series

average_candle_body(open_, close, period=14)[source]

Simple moving average of absolute body sizes.

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • period (int, default: 14) – SMA look-back period.

  • open_ (Series)

Return type:

Series

Returns:

Smoothed average body size.

Example

>>> avg_body = average_candle_body(open_, close, period=14)
Parameters:
Return type:

Series

candle_momentum(open_, close, period=5)[source]

Sum of (close - open) over the last period bars.

A positive value indicates net bullish momentum; negative indicates bearish momentum.

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • period (int, default: 5) – Number of bars to sum.

  • open_ (Series)

Return type:

Series

Returns:

Cumulative close-minus-open over the window.

Example

>>> mom = candle_momentum(open_, close, period=5)
Parameters:
Return type:

Series

body_gap(open_, close)[source]

Gap between consecutive candle bodies.

Computed as open[i] - close[i-1], i.e. the distance between the current open and the previous close.

Parameters:
  • open – Open prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

Body gap for each bar (positive = gap up, negative = gap down).

Example

>>> gap = body_gap(open_, close)
Parameters:
Return type:

Series

inside_bar(high, low)[source]

Detect inside bars.

An inside bar has a high below the previous high and a low above the previous low (the bar is fully contained within the prior bar’s range).

Interpretation:
  • Consolidation / contraction – the market is building energy.

  • Breakout of the inside bar’s range often leads to a significant directional move.

  • Multiple consecutive inside bars = stronger breakout.

Trading rules:
  • Place a buy stop above the inside bar’s high and a sell stop below its low. Trade whichever triggers first.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

Return type:

Series

Returns:

Boolean series (True where an inside bar is detected).

Example

>>> ib = inside_bar(high, low)
outside_bar(high, low)[source]

Detect outside bars (engulfing range).

An outside bar has a high above the previous high and a low below the previous low (the bar’s range completely engulfs the prior bar’s range).

Interpretation:
  • High volatility bar showing a battle between buyers and sellers.

  • The close direction determines who won: close near the high = bullish; close near the low = bearish.

  • Often marks a reversal or a volatility breakout.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

Return type:

Series

Returns:

Boolean series (True where an outside bar is detected).

Example

>>> ob = outside_bar(high, low)
pin_bar(open_, high, low, close, shadow_ratio=2.0)[source]

Detect pin bars.

A pin bar has a long shadow that is at least shadow_ratio times the body size. A bullish pin bar (1) has a long lower shadow; a bearish pin bar (-1) has a long upper shadow.

Interpretation:
  • Bullish pin bar (1): Long lower shadow shows strong rejection of lower prices. Buy signal at support.

  • Bearish pin bar (-1): Long upper shadow shows strong rejection of higher prices. Sell signal at resistance.

  • One of the most widely used price action signals.

  • Most reliable at key support/resistance levels or after a sustained trend.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • shadow_ratio (float, default: 2.0) – Minimum shadow-to-body ratio to qualify (default 2.0).

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish pin bar), -1 (bearish pin bar), or 0.

Example

>>> pb = pin_bar(open_, high, low, close)
Parameters:
Return type:

Series

Price Action

Higher highs/lows, swing points, gap analysis, narrow range, key reversals.

Price action analysis.

Functions for detecting structural price action features such as swing points, trend bars, gaps, range expansion/contraction, and reversal bars. All functions accept pd.Series inputs and return pd.Series (or dict where noted).

higher_highs_lows(high, low, period=5)[source]

Detect sequences of HH/HL (uptrend) or LH/LL (downtrend).

Compares rolling highest-high and lowest-low over period bars to determine whether the market is making higher highs & higher lows (uptrend = 1), lower highs & lower lows (downtrend = -1), or neither (0).

Interpretation:
  • 1 (HH+HL): Classic uptrend structure. Price is making higher highs and higher lows – the textbook definition of an uptrend.

  • -1 (LH+LL): Classic downtrend structure.

  • 0: No clear trend – consolidation, range, or transition.

  • When the sequence breaks (e.g. first lower low in an uptrend), it is an early warning of potential trend reversal.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 5) – Look-back window for swing comparison.

Return type:

Series

Returns:

1 (uptrend / HH+HL), -1 (downtrend / LH+LL), or 0.

Example

>>> trend = higher_highs_lows(high, low, period=5)
swing_high(high, lookback=2, lookahead=2)[source]

Detect swing highs.

A swing high is a bar whose high is greater than the highs of the lookback bars before it and the lookahead bars after it.

Parameters:
  • high (Series) – High prices.

  • lookback (int, default: 2) – Number of bars to look back.

  • lookahead (int, default: 2) – Number of bars to look ahead.

Return type:

Series

Returns:

Boolean series (True at swing highs).

Example

>>> sh = swing_high(high, lookback=2, lookahead=2)
swing_low(low, lookback=2, lookahead=2)[source]

Detect swing lows.

A swing low is a bar whose low is less than the lows of the lookback bars before it and the lookahead bars after it.

Parameters:
  • low (Series) – Low prices.

  • lookback (int, default: 2) – Number of bars to look back.

  • lookahead (int, default: 2) – Number of bars to look ahead.

Return type:

Series

Returns:

Boolean series (True at swing lows).

Example

>>> sl = swing_low(low, lookback=2, lookahead=2)
trend_bars(close)[source]

Count consecutive up/down bars.

Returns a running count: positive values for consecutive up bars (close > previous close), negative values for consecutive down bars (close < previous close). The count resets to 0 on a flat bar.

Parameters:

close (Series) – Close prices.

Return type:

Series

Returns:

Consecutive bar count (positive = up streak, negative = down streak).

Example

>>> streaks = trend_bars(close)
gap_analysis(open_, high, low, close, avg_range_period=20, breakaway_threshold=1.5)[source]

Detect and classify gaps.

Gaps are classified as:

  • common — gap size is below the average range

  • breakaway — gap size exceeds breakaway_threshold times the average range

  • exhaustion — gap that occurs after a sustained move (approximated by comparing the current close to a look-back SMA)

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • avg_range_period (int, default: 20) – Period for computing the average range.

  • breakaway_threshold (float, default: 1.5) – Multiplier of average range for breakaway classification.

  • open_ (Series)

Return type:

dict[str, Series]

Returns:

Dictionary with keys gap_size, gap_direction, and gap_type.

  • gap_size — absolute gap size

  • gap_direction — 1 (gap up), -1 (gap down), 0 (no gap)

  • gap_type — categorical string ("common", "breakaway", "exhaustion", or "" for no gap)

Example

>>> result = gap_analysis(open_, high, low, close)
>>> result["gap_type"]
Parameters:
Return type:

dict[str, Series]

range_expansion(high, low, period=14, threshold=1.5)[source]

Detect range expansion (current range significantly above average).

Returns True when (high - low) > threshold * avg_range.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 14) – Look-back for average range.

  • threshold (float, default: 1.5) – Multiplier of average range to trigger expansion.

Return type:

Series

Returns:

Boolean series (True where range is expanded).

Example

>>> expanded = range_expansion(high, low)
narrow_range(high, low, period=4)[source]

NR4/NR7 detection — narrowest range in period bars.

Returns True when the current bar’s range is the smallest in the last period bars (including itself). period=4 gives NR4; period=7 gives NR7.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 4) – Look-back window (default 4 for NR4).

Return type:

Series

Returns:

Boolean series (True at narrow-range bars).

Example

>>> nr4 = narrow_range(high, low, period=4)
>>> nr7 = narrow_range(high, low, period=7)
wide_range_bar(high, low, period=14, threshold=1.5)[source]

Wide Range Bar (WRB): range > threshold * average range.

Parameters:
  • high (Series) – High prices.

  • low (Series) – Low prices.

  • period (int, default: 14) – Look-back for average range.

  • threshold (float, default: 1.5) – Multiplier (default 1.5).

Return type:

Series

Returns:

Boolean series (True at wide-range bars).

Example

>>> wrb = wide_range_bar(high, low)
key_reversal(open_, high, low, close)[source]

Detect key reversal bars.

A bullish key reversal (1) makes a new low (below the previous low) but closes above the previous close.

A bearish key reversal (-1) makes a new high (above the previous high) but closes below the previous close.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish key reversal), -1 (bearish key reversal), or 0.

Example

>>> kr = key_reversal(open_, high, low, close)
Parameters:
Return type:

Series

pivot_reversal(open_, high, low, close)[source]

Detect two-bar pivot reversal patterns at swing points.

A bullish pivot reversal (1): the previous bar makes a lower low than its predecessor, and the current bar closes above the previous bar’s high.

A bearish pivot reversal (-1): the previous bar makes a higher high than its predecessor, and the current bar closes below the previous bar’s low.

Parameters:
  • open – Open prices.

  • high (Series) – High prices.

  • low (Series) – Low prices.

  • close (Series) – Close prices.

  • open_ (Series)

Return type:

Series

Returns:

1 (bullish pivot reversal), -1 (bearish pivot reversal), or 0.

Example

>>> pr = pivot_reversal(open_, high, low, close)
Parameters:
Return type:

Series