Use indicators in Python¶
Build a signal by calculating an indicator from market history and comparing its current value with a threshold or another indicator. Python strategies can use the platform's supplied functions directly, or import additional functions from TAP, the technical-analysis library.
Start with a complete rule¶
This example requests ten units when RSI is above 50 and close is above its 50-bar EMA. It requests an exit when close falls below that EMA.
from math import isfinite
symbol = "TCS"
def on_tick():
if len(close) < 50:
return
strength = rsi(close, 14)[0]
average = ema(close, 50)[0]
if not (isfinite(strength) and isfinite(average)):
return
if position.is_flat and strength > 50 and close[0] > average:
long(10)
elif position.is_long and close[0] < average:
close()
close is an input series. rsi(close, 14) returns an indicator series; [0] selects its current value. The history guard requires 50 available closes, and the finite-value check avoids using missing readings. An EMA can still depend on how its earlier history was initialised.
The example uses injected rsi and ema, so no indicator import is needed in this strategy shape. Their implementations come from TAP, which must be present in the running environment. An import statement cannot install a missing package.
Find an indicator¶
Use the Python indicator library for explicit call forms, defaults, result units and the supplied component names. Use more indicators with TAP for explicit imports and multi-line results. These pages stay in the Python guide; you do not need to translate TradeScript examples yourself.
For Alpha Lab's optional signal namespace, read use Alpha Lab signals. It has its own installation pin, full-bar requirements and NaN/result conventions.
Choose the input explicitly¶
| Python call | Input and meaning |
|---|---|
sma(close, 20) |
Mean of the latest 20 closes, including now. |
sma(high, 20) |
Average the high prices instead. |
rsi(close, period=14) |
RSI of close; Python permits named arguments. |
atr(bars, 14) |
ATR needs high, low and close together. |
vwma(bars, 14) |
Volume-weighted close needs price and volume. |
sma(close) |
Explicit input with the default SMA period, 20. |
Always supply the input in Python. rsi(14) and atr(14) are TradeScript shorthand, not Python indicator calls. Periods count the actual input bars; changing when a rule is evaluated does not itself resample its price history. See price data and bars.
Separate histories remain separate inputs, even in the same tick:
daily_mean = sma(security("TCS", "1d"), 2)[0]
hourly_mean = sma(security("TCS", "1h"), 2)[0]
Use this fragment after both histories have enough completed bars. If the two
latest daily closes are 10 and the hourly closes are 100, the means are 10 and
100 regardless of call order. Each security request uses its own timeframe
and requested history length. Earlier indicator memoization could reuse the
first timeframe's result for the second; rerun affected multi-timeframe backtests.
Repeated ordinary field-series calls still reuse work within a tick, without
sharing results with a different symbol or later tick.
Current values and history¶
For a series result, [0] means now, [1] means one bar ago, and [2] means two bars ago. A history offset counts observations; it is not a function parameter.
current_rsi = rsi(close, 14)[0]
previous_rsi = rsi(close, 14)[1]
recovering = current_rsi > 50 and previous_rsi <= 50
Use this fragment inside on_tick() after checking sufficient history and finite readings. It detects a crossing of a fixed threshold. A state test such as current_rsi > 50 can remain true on subsequent bars.
For two series, crossover(ema(close, 20), ema(close, 50)) checks both their current and previous values. crossunder reverses the relationship. Passing two current scalar readings loses the history those helpers require.
Helpers return a value now¶
Core helpers are supplied independently of TAP. They do not all return an indicator series.
| Call | Result and warmup |
|---|---|
mean(close, 20) |
Scalar mean of up to 20 available values; can use a shorter window. |
highest(high, 20) |
Scalar maximum including now; requires the complete window. |
lowest(low, 20) |
Scalar minimum including now; requires the complete window. |
stdev(close, 20) |
Scalar sample standard deviation; 0 with fewer than two values. |
change(close, 14) |
Scalar price difference from 14 bars ago; needs 15 values. |
pct_change(close, 14) |
Scalar relative change as a fraction; 0.05 means 5%. |
Do not append [0] or [1] to those scalar results. To read a previous moving-average value, use a series such as sma(close, 20)[1]. To compare against a previous high window, use donchian_upper(bars, 20)[1]; the unshifted window includes the current high.
Select the correct line¶
Injected macd(close, 12, 26, 9) returns the MACD line; macd_signal(...) and macd_hist(...) select its siblings. The same pattern provides individual band, directional and stochastic lines. Raw TAP calls may instead return a container of several series. Read the two call styles before mixing them.
Check units and missing data¶
Moving averages are price levels; ATR is a price distance; RSI is a 0–100 reading. roc(close, 14)[0] reports percentage points: 5 means 5%, while pct_change(close, 14) reports 0.05 for that same move. Neither value is a position size.
Supply enough history for every input and previous value. Volume calculations also require meaningful volume, and OHLC calculations require high and low. Some functions initialise early values; others return missing readings. The library restrictions identify known calculation issues, including modified_rsi.
Explore the functions Python indicator library →