Unstable Period
TL;DR: Some indicators need a warm-up before their output settles. TA-Lib can discard those bars for you, so unstable values never reach your application.
Why it exists
Some indicators have "memory". Each output depends on the previous one, seeded from the start of the data. An Exponential Moving Average is the classic example: the seed's effect is large at first, and decays with each bar until the result is stable.
This is inherent to the algorithms, not something specific to TA-Lib: every implementation has to seed the recursion somewhere.
What to do
There are three distinct approaches, from the most common to the most rigorous:
Ignore the problem. What most charting sites do, and usually fine: the latest bar has plenty of history behind it. Nothing warns you when it doesn't; a short series, or a back-test on the earliest bars, quietly uses bad values.
Scrub it yourself. TA-Lib stays at its default (unstable period
0) and returns everything it can compute; your code decides how many leading outputs to drop.Let TA-Lib do it. Set an unstable period and the function stops emitting that many leading values, the ones the seed still distorts.
API
TA_RetCode TA_SetUnstablePeriod( TA_FuncUnstId id, unsigned int unstablePeriod );
unsigned int TA_GetUnstablePeriod( TA_FuncUnstId id );
/* Strip 30 extra bars from every EMA-based calculation: */
TA_SetUnstablePeriod( TA_FUNC_UNST_EMA, 30 );
/* Apply the same unstable period to ALL affected functions at once: */
TA_SetUnstablePeriod( TA_FUNC_UNST_ALL, 30 );use ta_lib::{Core, FuncUnstId};
// Strip 30 extra bars from every EMA-based calculation:
let core = Core::builder()
.unstable_period(FuncUnstId::EMA, 30)
.build()?;
// Apply the same unstable period to ALL affected functions at once:
let core = Core::builder()
.unstable_period(FuncUnstId::ALL, 30)
.build()?;
let n = core.get_unstable_period(FuncUnstId::EMA)?; // read it backimport io.github.talib.Core;
import io.github.talib.FuncUnstId;
// Strip 30 extra bars from every EMA-based calculation:
Core core = Core.builder()
.unstablePeriod(FuncUnstId.EMA, 30)
.build();
// Apply the same unstable period to ALL affected functions at once:
Core all = Core.builder()
.unstablePeriod(FuncUnstId.ALL, 30)
.build();
int n = core.unstablePeriod(FuncUnstId.EMA); // read it backusing TALib;
// Strip 30 extra bars from every EMA-based calculation:
Core core = Core.Builder()
.UnstablePeriod(FuncUnstId.EMA, 30)
.Build();
// Apply the same unstable period to ALL affected functions at once:
Core all = Core.Builder()
.UnstablePeriod(FuncUnstId.ALL, 30)
.Build();
int n = core.UnstablePeriod(FuncUnstId.EMA); // read it backid selects which function to affect. The period sets how many warm-up bars that function discards; the larger the value, the later the first output. The default, 0, discards nothing: you get every value the function can compute.
The setting follows the function wherever it runs: whether you call it directly, or another indicator uses it internally. The EMA id therefore affects EMA itself and every indicator built on one, such as MACD and DEMA.
Functions with an unstable period
ADX, ATR, CMO, DX, EMA, HT_DCPERIOD, HT_DCPHASE, HT_PHASOR, HT_SINE, HT_TRENDLINE, HT_TRENDMODE, KAMA, MAMA, MINUS_DI, MINUS_DM, NATR, PLUS_DI, PLUS_DM, RSI, T3, RMA, HA, RVI.
| Language | Id | Enum |
|---|---|---|
| C | TA_FUNC_UNST_<NAME> | ta_defs.h |
| Rust | FuncUnstId::<NAME> | types.rs |
| Java | FuncUnstId.<NAME> | FuncUnstId.java |
| C# | FuncUnstId.<NAME> | FuncUnstId.cs |
<NAME> may also be ALL, which targets every function above at once.