iir
First introduced in version: 2.00.19/3.00.6
Syntax
iir(X, b, a)
Details
Applies an infinite impulse response (IIR) filter to the input data X and returns the filtered result. An IIR filter uses previous output values as feedback, allowing them to achieve sharper transition bands with a much lower filter order.
The mathematical expression is: a[0]·y[n] = (b[0]·x[n] + b[1]·x[n-1] + … + b[M]·x[n-M]) - (a[1]·y[n-1] + … + a[N]·y[n-N]), where b denotes the numerator coefficients and a denotes the denominator coefficients.
-
Leading null values in the input are ignored in the calculation, and the corresponding output are also NULL. Any null values after the leading null values are treated as 0.
-
This function is equivalent to Python's
scipy.signal.lfilter(b, a, X), except for its handling of missing values.scipy.signal.lfilterdoes not treat NaN values specially, so NaNs are included in the filtering process and propagate through subsequent outputs.
Parameters
X is a regular vector of numeric type specifying the data to be filtered.
b is a non-empty regular vector of numeric type specifying the numerator coefficients of the IIR filter.
a is a non-empty regular vector of numeric type specifying the denominator coefficients of the IIR filter.
Returns
Returns a result of the same form and length as the input X.
Examples
Example 1. Apply an IIR filter to a vector.
x = 1 2 3 4 5
b = 0.2 0.2
a = 1 -0.5
iir(x, b, a)
// output: [0.2,0.7,1.35,2.075,2.8375]
x = [1, 2, NULL, 4] // equivalent to [1, 2, 0, 4]
b = 0.2 0.2
a = 1 -0.5
iir(x, b, a)
// output: [0.2,0.7,0.75,1.175]
Example 2. The moving average crossover strategy is one of the most classic trend-following strategies in quantitative trading. It uses a fast EMA and a slow EMA: a buy signal is generated when the fast EMA crosses above the slow EMA, and a sell signal is generated when the fast EMA crosses below the slow EMA. An EMA is essentially a first-order IIR filter.
Compared with an FIR filter that provides a similar degree of smoothing, an IIR filter requires only two coefficients. This offers significant computational advantages when backtesting strategies across hundreds of stocks in a broad market universe.
The following example simulates 1-minute bar data for a single trading day of a stock. Two first-order IIR filters, alphaFast (corresponding to a 10-period EMA) and alphaSlow (corresponding to a 30-period EMA), are used to extract the fast and slow trend lines, respectively, and generate crossover signals.
// 1. Create the catalog, database, and table
if(!existsCatalog("FinanceData")){
createCatalog("FinanceData")
}
go
use catalog FinanceData
if(!existsDatabase("FinanceData.kline")){
create database kline
partitioned by VALUE(2026.06.01..2026.06.30),
engine='TSDB'
}
go
if(!existsTable("FinanceData.kline", "min1")){
create table kline.min1 (
SecurityID SYMBOL,
TradeDate DATE,
BarTime TIMESTAMP,
Open DOUBLE,
High DOUBLE,
Low DOUBLE,
Close DOUBLE,
Volume LONG
)
partitioned by TradeDate,
sortColumns = [`SecurityID, `BarTime],
keepDuplicates = ALL
}
// 2. Generate sample data: simulate 240 one-minute bars for 600519.SH on a trading day
n = 240
idx = 0..(n - 1)
baseTime = 2026.06.02T09:30:00.000
barTime = baseTime + idx * 60000
trendComponent = 1800.0 + 10.0 * sin(2.0 * pi * idx / n * 2.0) + cumsum(rand(0.2, n) - 0.1)
noise = norm(0.0, 1.0, n)
closePrice = round(trendComponent + noise, 2)
openPrice = round(closePrice + norm(0.0, 0.5, n), 2)
highBase = iif(openPrice > closePrice, openPrice, closePrice)
lowBase = iif(openPrice < closePrice, openPrice, closePrice)
highPrice = round(highBase + abs(norm(0.0, 0.3, n)), 2)
lowPrice = round(lowBase - abs(norm(0.0, 0.3, n)), 2)
volume = long(rand(10000, n) + 100)
t = table(
symbol(take("600519.SH", n)) as SecurityID,
take(2026.06.02, n) as TradeDate,
barTime as BarTime,
openPrice as Open,
highPrice as High,
lowPrice as Low,
closePrice as Close,
volume as Volume
)
// 3. Insert the data
kline.min1.append!(t)
// 4. Load the bar data
raw = select BarTime, Close
from kline.min1
where SecurityID = `600519.SH
and TradeDate = 2026.06.02
order by BarTime
// 5. Compute the fast and slow EMA lines using IIR filters
alphaFast = 2.0 / (10 + 1)
alphaSlow = 2.0 / (30 + 1)
emaResult = select
BarTime,
Close,
iir(Close, [alphaFast], [1.0, -(1.0 - alphaFast)]) as emaFast,
iir(Close, [alphaSlow], [1.0, -(1.0 - alphaSlow)]) as emaSlow
from raw
// 6. Generate crossover signals
signals = select
BarTime,
Close,
emaFast,
emaSlow,
iif(
emaFast > emaSlow and prev(emaFast) <= prev(emaSlow),
"BUY",
iif(
emaFast < emaSlow and prev(emaFast) >= prev(emaSlow),
"SELL",
"HOLD"
)
) as signal
from emaResult
order by BarTime
// 7. Query all buy and sell signals
select *
from signals
where signal != "HOLD"
order by BarTime
Related Functions: fir
