Investment Studio > Expressions > Functions > Indicator > TSI
float array[*][2] tsi(float array[*][2] dc, integer long_days, integer short_days)
Returns a two-column array containing dates (first column) and corresponding True Strength Index (TSI) values (second column). Given n input rows in dc, n - 1 (or fewer) rows are returned. Due to the double exponential smoothing built into this indicator, roughly 2 *(long_days + short_days) rows of input are needed before output stabilizes.
dc is a two-column array containing dates (first column) and corresponding daily closes (second column). The array is assumed to be time-sorted, with earlier dates preceding later dates.
Automatic type conversion allows the use of date strings as arguments instead of explicit date values.
long_days > 0 is the timescale of the first built-in EMA.
short_days > 0 is the timescale of the second built-in EMA (chained after the first one).
Interpretation
TSI is an indicator of price trend direction and strength. It's defined as the ratio between the double-smoothed 1 day momentum, EMA(EMA(MO(dc, 1), long_days), short_days), and the double-smoothed absolute value of 1 day momentum. Its output will therefore spend most of its time oscillating between -1 and 1. A positive value means that the price trend is up (more so for larger positive values), a negative value that the price trend is down (more so for larger negative values).
Although smoothing and scaling are different, the basic concept (a normalized measure of daily gains vs. daily losses) is the same as for RSI, and interpretation goes along the same lines. The main advantage over RSI is less volatility, the main disadvantage a slightly larger time delay: the time lag of a filter chain is the sum of the time lags of each filter in the chain, so the TSI lags price by the delay introduced by EMA(long_days) plus the delay introduced by EMA(short_days).
For a real life example, consider KLM (NYSE:KLM) from January 1 to December 31, 2001:

The top chart shows daily prices in standard candlestick form. The bottom chart shows TSI with long_days = 9 and short_days = 3. In the top chart, days marked in green are zero crossings from below (price trend turning up); days marked in red are zero crossings from above (price trend turning down). Compare these charts with the corresponding RSI example.
Note that the TSI's built-in long and short EMAs are chained, not subtracted. The TSI therefore doesn't focus on cycle lengths between short_days and long_days, as it's sometimes misconstrued to do. The amplitude response of a filter chain is the pointwise product of the amplitude responses of each filter in the chain, so the role of the two EMA length arguments is simply to allow the definition of an amplitude response which falls off faster (for shorter cycles) than two chained EMAs of length short_days, but slower than two chained EMAs of length long_days (assuming that short_days < long_days; the actual order of the two EMAs is not important).
To analyze the effect of double EMA smoothing, we can exploit the fact that the frequency response of any linear, time-invariant filter is just the Fourier transform of the filter's impulse response (the filter's output when the input sequence is a unit impulse, i.e. a single 1 surrounded by zeros, effectively all the way both to positive and to negative infinity). This means that we can visualize the frequency response of an EMA chain by passing a unit impulse through it and computing the Fourier transforms of its output.
With the definitions
_n = 1024
_short_days = 3
_long_days = 9
_impulse = index(m1(_n), 0, 1)
_ema_short = lopass(make_ema(_short_days), 1, array(_impulse))
_ema_long = lopass(make_ema(_long_days), 1, array(_impulse)))
_ema_both = lopass(make_ema(_short_days), 1, array(_ema_long)))
_response_short = fftp(array(_ema_short))
_response_long = fftp(array(_ema_long))
_response_both = fftp(array(_ema_both))
the graph sources
=_n * index(array(_response_short), x + 1, 1)
=_n * index(array(_response_long), x + 1, 1)
=_n * index(array(_response_both), x + 1, 1)
(where the "+ 1" is to skip the zeroth, constant "harmonic") yield the following amplitude responses for EMA(3) (red), EMA(9) (green) and EMA(EMA(9), 3) (blue):

At the low end of the spectrum (long cycles), the double EMA is almost indistinguishable from the long EMA, but it does a much better job suppressing shorter cycles. With the EMA lengths in the example (3 and 9 days) the difference becomes significant somewhere around the 50th harmonic, corresponding to cycle durations of 1024 / 50 » 20 days and shorter.
The price for this improved noise reduction becomes apparent when one plots the the graph sources
=index(array(_response_short), x + 1, 2)
=index(array(_response_long), x + 1, 2)
=index(array(_response_both), x + 1, 2)
to get the following phase responses:

The EMA(EMA(9), 3) trough around the 140th harmonic introduces a phase delay of roughly 1.4 radians (22% of the 2 * PI making up a full cycle). In terms of time, the lag is 0.22 * 1024 / 140 » 1.6 days. In comparison, the max delay for EMA(3) is roughly 0.5 radians around the 170th harmonic, or approximately half a day; the max delay for EMA(9) is roughly 0.9 radians around the 110th harmonic, or approximately 1.3 days.
Example
Assuming standard US date format settings,
=tsi({{"1/1/1990", 12}, {"1/2/1990", 11}, {"1/3/1990", 12}}, 3, 9)
returns {{32875, -1}, {32876, -0.130434782608696}}. 32875 is the date code for 1/2/1990; -1 is the TSI computed for that date (1/2/1990 is a down day, and also the only day in the filter chains, so the TSI is bottomed out). 32876 is the date code for 1/3/1990; -0.13... is the TSI computed for that date.