Analysis¶
Every instrument object can analyse its own price history. A share, an index or a commodity future has 209 analysis methods: moving averages, oscillators, candlestick pattern detectors, summary statistics, crossover signals, a backtest runner and performance measures such as the Sharpe ratio. You call one on the instrument, such as reliance.relative_strength_index(window=14, days=90), and it fetches the candles from UBI, runs the calculation and hands back the candles with the result added as a new column.
The methods are not written on Instrument itself. They live in fourteen small classes under src/tradingmachine/assets/analysis/, one per group of related calculations, and Instrument inherits all fourteen. Most of the calculations come from TA-Lib, a widely used C library of technical indicators, and follow its function groups; the statistics, the signals, the backtest and the performance measures are this library's own. Every asset basket inherits the same fourteen classes, because a basket supplies prices too.
How a method works¶
Every analysis method that works on candles follows the same four steps, which the sequence diagram below traces for relative_strength_index.
sequenceDiagram
autonumber
participant Y as Your code
participant M as relative_strength_index
participant P as prices()
participant U as UBI
participant T as TA-Lib
Y->>M: window=14, days=90
M->>P: interval, from_date, to_date, days, adjusted
P->>U: GET /api/instruments/prices
U-->>P: candles, or none
P-->>M: DataFrame, or None
alt no candles
M-->>Y: None
else candles
M->>T: RSI(close, timeperiod=14)
T-->>M: one value per candle
M-->>Y: the candles with an rsi_14 column added
end
Three things follow from this design, and each is worth knowing before you call the methods in a loop.
- Each call fetches its own candles. Two indicators on the same instrument send two requests. That is deliberate: UBI runs on the same machine and keeps its own copy of the candles in Redis, so a repeated request is cheap, and the library keeps no cache of its own.
- No candles means
None, not an error. When UBI has no candles for the range,pricesreturnsNone, and so does every method built on it. That is what happens for every instrument in a family UBI stores no candles for, as the table below shows. - The early rows are empty. An indicator needs a run of candles before it has a value, so the first rows of its column are
NaN. A 14-candle RSI has nothing for its first 14 rows, and the Hilbert transform indicators need 32 to 63 candles before their first value. Ask for a longer range than the window you want to look at.
The common arguments¶
Every method that fetches candles takes the same five arguments as prices, after its own. The table below lists them. Give either days, or from_date and to_date, but not both.
| Name | Type | Default | Description |
|---|---|---|---|
interval |
str |
"day" |
The candle length, such as day or 5minute |
from_date |
datetime.date or str |
None |
The first day of the range, as a date or YYYY-MM-DD |
to_date |
datetime.date or str |
None |
The last day of the range |
days |
int |
None |
The number of days to count back from today |
adjusted |
bool |
True |
Whether prices are adjusted for splits and bonuses, for the segments UBI adjusts |
Each method's own arguments use the library's spelled-out names rather than TA-Lib's. The window length is window, not TA-Lib's timeperiod and not period, and the candle column to work on is column, which defaults to close.
The window argument is window
Passing a name the method does not have fails in Python before any request is sent. The error below was captured on 2026-09-26 from reliance.simple_moving_average(period=5).
The correct call is reliance.simple_moving_average(window=5, days=90).
The fourteen classes¶
The table below lists the fourteen analysis classes in the order Instrument inherits them, with the number of public methods in each. The counts were taken from the code with a short script on 2026-09-29 and add up to 209. The thirteen older classes add up to 192, and PerformanceMeasures was added as the fourteenth on 2026-09-28.
| Class | Module | Methods | What it holds | Each method returns | Page |
|---|---|---|---|---|---|
PriceStatistics |
price_statistics |
39 | Highs, lows, means, spreads and quantiles of prices, volumes and returns | A number, a summary, a histogram or a narrowed frame | Statistics |
OverlapStudies |
overlap_studies |
12 | Moving averages, Bollinger bands, parabolic SAR | The candles with columns added | Indicators |
MomentumIndicators |
momentum_indicators |
28 | MACD, RSI, ADX, stochastics and other oscillators | The candles with columns added | Indicators |
VolumeIndicators |
volume_indicators |
3 | Chaikin accumulation distribution, on balance volume | The candles with a column added | Indicators |
CycleIndicators |
cycle_indicators |
6 | The Hilbert transform family | The candles with columns added | Indicators |
PriceTransforms |
price_transforms |
4 | Average, median and typical price, weighted close | The candles with a column added | Statistics |
VolatilityIndicators |
volatility_indicators |
3 | True range and average true range | The candles with a column added | Indicators |
StatisticFunctions |
statistic_functions |
8 | Beta, correlation, linear regression, standard deviation | The candles with columns added | Statistics |
MathTransforms |
math_transforms |
15 | Trigonometric, logarithmic and rounding functions | The candles with a column added | Statistics |
MathOperators |
math_operators |
10 | Adding, dividing, rolling highs and lows | The candles with columns added | Statistics |
CandlestickPatterns |
candlestick_patterns |
61 | TA-Lib's candlestick pattern recognisers | The candles with a column of 100, -100 or 0 | Patterns |
Signals |
signals |
2 | Crossovers and crossunders between two columns | A copy of your frame with a bool column | Signals and backtests |
StrategyBacktests |
strategy_backtests |
1 | A backtest of a backtesting strategy |
A pandas Series of statistics | Signals and backtests |
PerformanceMeasures |
performance_measures |
17 | Returns, volatility, Sharpe, Sortino and Calmar ratios, drawdowns, value at risk and measures against a benchmark | A number, a DataFrame of drawdowns or a pandas Series summary | Performance measures |
All fourteen inherit a small base class, PriceAnalysis, which declares prices and raises NotImplementedError from it. That lets each module be written and read on its own, without importing the instrument classes. Instrument supplies the real prices, which reads UBI.
The chart below shows the same counts. Candlestick patterns and price statistics make up almost half of the total.
Which instruments have candles¶
An analysis method can only work where UBI stores candles, and it stores them for a minority of segments. The table below lists what is known, family by family. Asset classes has the full matrix.
| Family | Classes with candles | Classes without |
|---|---|---|
| Equities | Equity (adjusted, with price_factor), EquityIndex |
The four derivative classes have not been checked |
| Fixed income | none | all six |
| Commodities | the four derivative classes | Commodity, CommodityIndex |
| Currencies | none | all six |
| Funds and trusts | ExchangeTradedFund (adjusted, with price_factor) |
InvestmentTrust |
| Mutual funds | none | MutualFund |
UBI's daily job loads only day candles. Intraday intervals such as 5minute are loaded into UBI by hand, so an intraday call usually returns None unless someone has loaded that instrument; on 2026-09-26, prices(interval="5minute", days=1) on RELIANCE returned None. UBI's page on price history explains what is loaded and from which broker.
A first example¶
The example below adds a 20-day simple moving average to RELIANCE's candles and marks the days its close crossed above it. It was not run for this page, because it needs a live UBI; the calls are taken from the method signatures.
from tradingmachine.assets import equities
reliance = equities.Equity(exchange="nse", symbol="RELIANCE")
frame = reliance.simple_moving_average(window=20, days=365)
crossings = reliance.is_cross_over(frame, "close", "sma_20")
print(crossings[crossings["cross_over"]][["datetime", "close", "sma_20"]])
The first call returns the candles with an sma_20 column. The second marks, in a new cross_over column, each row where the close was at or below the average on the previous row and above it on this one.
The pages in this section¶
Each page lists every method in its groups, with the method's own arguments and the column it adds.
-
Indicators
Overlap studies, momentum, volume, volatility and cycle indicators: 52 methods.
-
Candlestick patterns
The 61 pattern recognisers and what their 100, -100 and 0 values mean.
-
Statistics and transforms
Price statistics, statistic functions, math operators and transforms, and price transforms: 76 methods.
-
Signals and backtests
Crossover detection and running a
backtestingstrategy over an instrument's candles. -
Performance measures
Returns, risk, drawdowns and comparison with a benchmark: 17 methods.