mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-07-27 17:27:43 +00:00
114 lines
5.0 KiB
Plaintext
114 lines
5.0 KiB
Plaintext
// Licensed under the Apache License, Version 2.0
|
|
// © mihakralj
|
|
//@version=6
|
|
indicator("True Strength Index (TSI)", "TSI", overlay=false)
|
|
|
|
//@function Calculates the True Strength Index and its signal line.
|
|
//@param src series float The source series.
|
|
//@param longLen simple int The lookback period for the first EMA smoothing (typically 25).
|
|
//@param shortLen simple int The lookback period for the second EMA smoothing (typically 13).
|
|
//@param signalLen simple int The lookback period for the signal line EMA (typically 13).
|
|
//@returns tuple [float, float] A tuple containing the TSI value and its signal line.
|
|
//@optimized for performance and dirty data
|
|
tsi(series float src, simple int longLen, simple int shortLen, simple int signalLen) =>
|
|
if longLen <= 0 or shortLen <= 0 or signalLen <= 0
|
|
runtime.error("Lengths must be greater than 0")
|
|
float mom = src - nz(src[1])
|
|
float absMom = math.abs(mom)
|
|
var float emaMomLong = na, var float emaMomLong_e = 1.0, var bool emaMomLong_warmup = true
|
|
var float emaMomShort = na, var float emaMomShort_e = 1.0, var bool emaMomShort_warmup = true
|
|
var float emaAbsMomLong = na, var float emaAbsMomLong_e = 1.0, var bool emaAbsMomLong_warmup = true
|
|
var float emaAbsMomShort = na, var float emaAbsMomShort_e = 1.0, var bool emaAbsMomShort_warmup = true
|
|
var float emaSignal = na, var float emaSignal_e = 1.0, var bool emaSignal_warmup = true
|
|
float alphaLong = 2.0 / math.max(longLen, 1)
|
|
float alphaShort = 2.0 / math.max(shortLen, 1)
|
|
float alphaSignal = 2.0 / math.max(signalLen, 1)
|
|
float smoothedMomLong = 0.0
|
|
float smoothedAbsMomLong = 0.0
|
|
float doubleSmoothedMom = 0.0
|
|
float doubleSmoothedAbsMom = 0.0
|
|
float tsiValue = 0.0
|
|
float signalLineValue = 0.0
|
|
if not na(mom)
|
|
if na(emaMomLong)
|
|
emaMomLong := 0.0
|
|
smoothedMomLong := mom
|
|
else
|
|
emaMomLong := alphaLong * (mom - emaMomLong) + emaMomLong
|
|
if emaMomLong_warmup
|
|
emaMomLong_e *= (1 - alphaLong)
|
|
smoothedMomLong := (1.0 / (1.0 - emaMomLong_e)) * emaMomLong
|
|
if emaMomLong_e <= 1e-10
|
|
emaMomLong_warmup := false
|
|
else
|
|
smoothedMomLong := emaMomLong
|
|
if na(emaMomShort)
|
|
emaMomShort := 0.0
|
|
doubleSmoothedMom := smoothedMomLong
|
|
else
|
|
emaMomShort := alphaShort * (smoothedMomLong - emaMomShort) + emaMomShort
|
|
if emaMomShort_warmup
|
|
emaMomShort_e *= (1 - alphaShort)
|
|
doubleSmoothedMom := (1.0 / (1.0 - emaMomShort_e)) * emaMomShort
|
|
if emaMomShort_e <= 1e-10
|
|
emaMomShort_warmup := false
|
|
else
|
|
doubleSmoothedMom := emaMomShort
|
|
if na(emaAbsMomLong)
|
|
emaAbsMomLong := 0.0
|
|
smoothedAbsMomLong := absMom
|
|
else
|
|
emaAbsMomLong := alphaLong * (absMom - emaAbsMomLong) + emaAbsMomLong
|
|
if emaAbsMomLong_warmup
|
|
emaAbsMomLong_e *= (1 - alphaLong)
|
|
smoothedAbsMomLong := (1.0 / (1.0 - emaAbsMomLong_e)) * emaAbsMomLong
|
|
if emaAbsMomLong_e <= 1e-10
|
|
emaAbsMomLong_warmup := false
|
|
else
|
|
smoothedAbsMomLong := emaAbsMomLong
|
|
if na(emaAbsMomShort)
|
|
emaAbsMomShort := 0.0
|
|
doubleSmoothedAbsMom := smoothedAbsMomLong
|
|
else
|
|
emaAbsMomShort := alphaShort * (smoothedAbsMomLong - emaAbsMomShort) + emaAbsMomShort
|
|
if emaAbsMomShort_warmup
|
|
emaAbsMomShort_e *= (1 - alphaShort)
|
|
doubleSmoothedAbsMom := (1.0 / (1.0 - emaAbsMomShort_e)) * emaAbsMomShort
|
|
if emaAbsMomShort_e <= 1e-10
|
|
emaAbsMomShort_warmup := false
|
|
else
|
|
doubleSmoothedAbsMom := emaAbsMomShort
|
|
if doubleSmoothedAbsMom != 0
|
|
tsiValue := 100 * (doubleSmoothedMom / doubleSmoothedAbsMom)
|
|
else
|
|
tsiValue := 0
|
|
if na(emaSignal)
|
|
emaSignal := 0.0
|
|
signalLineValue := tsiValue
|
|
else
|
|
emaSignal := alphaSignal * (tsiValue - emaSignal) + emaSignal
|
|
if emaSignal_warmup
|
|
emaSignal_e *= (1 - alphaSignal)
|
|
signalLineValue := (1.0 / (1.0 - emaSignal_e)) * emaSignal
|
|
if emaSignal_e <= 1e-10
|
|
emaSignal_warmup := false
|
|
else
|
|
signalLineValue := emaSignal
|
|
else
|
|
tsiValue := nz(tsiValue[1], 50.0)
|
|
signalLineValue := nz(signalLineValue[1], 50.0)
|
|
[tsiValue, signalLineValue]
|
|
// ---------- Main loop ----------
|
|
// Inputs
|
|
i_source = input.source(close, "Source")
|
|
i_longLen = input.int(25, "Long Length", minval=1)
|
|
i_shortLen = input.int(13, "Short Length", minval=1)
|
|
i_signalLen = input.int(13, "Signal Length", minval=1)
|
|
|
|
// Calculation
|
|
[tsi_value, signal_line] = tsi(i_source, i_longLen, i_shortLen, i_signalLen)
|
|
|
|
// Plot
|
|
plot(tsi_value, "TSI", color=color.blue, linewidth=2)
|
|
plot(signal_line, "Signal Line", color=color.red, linewidth=2)
|