fir

First introduced in version: 2.00.19/3.00.6

Syntax

fir(X, b)

Details

Applies a Finite Impulse Response (FIR) filter to the input data X and returns the filtered result.

A FIR filter performs linear filtering via convolution. Its output depends only on the weighted sum of the current and previous inputs, so the system is inherently stable and readily designed with linear phase.

The mathematical expression is: y[n] = b[0]·x[n] + b[1]·x[n-1] + … + b[M]·x[n-M], where b denotes the filter coefficients and M is the filter order.

Note:
  • 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, [1.0], X), except for its handling of missing values. scipy.signal.lfilter does 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 FIR filter.

Returns

Returns a result of the same form and length as the input X.

Examples

Example 1. Apply a FIR filter to a vector.

x = 1 2 3 4 5
b = 0.2 0.3 0.5
fir(x, b)
// output: [0.2,0.7,1.7,2.7,3.7]

x = [1, 2, NULL, 4]  // equivalent to [1, 2, 0, 4]
b = 0.5 0.5
fir(x, b)
// output: [0.5,1.5,1,2]

Example 2. In high-frequency trading, tick-by-tick trade prices contain substantial microstructure noise. A FIR filter can smooth the price series without introducing phase distortion, making it ideal for latency-insensitive scenarios that require waveform accuracy (e.g., post-market factor computation).

The following example simulates 1,000 tick records for a stock on a single trading day. It applies a 5th-order equal-weight FIR low-pass filter (essentially a simple moving average in filter form) to denoise the price series.

// 1. Create the database and table
if(existsCatalog("financeData")){
    dropCatalog("financeData")
}

createCatalog("financeData")
go
use catalog financeData

create database trades
partitioned by VALUE(2026.06.01..2026.06.30), HASH([SYMBOL, 16]),
engine='TSDB'
go
create table trades.tick (
    SecurityID SYMBOL,
    TradeDate DATE,
    TradeTime TIMESTAMP,
    TradePrice DOUBLE,
    TradeVolume INT
)
partitioned by TradeDate, SecurityID,
sortColumns = [`SecurityID, `TradeTime],
keepDuplicates = ALL

// 2. Generate sample data: simulate 1,000 tick records for 600519.SH on a trading day
n = 1000
idx = 0..(n - 1)
baseTime = 2026.06.02T09:30:00.000
ts = baseTime + idx * 3000           // one tick every 3 seconds

// Simulate prices: random walk around 1800 + random noise
cumReturns = cumsum(rand(0.2, n) - 0.1)
noise = norm(0.0, 0.3, n)  // overlay high-frequency noise
prices = 1800.0 + cumReturns + noise
volumes = rand(100, n) + 1

t = table(
    symbol(take("600519.SH", n)) as SecurityID,
    take(2026.06.02, n) as TradeDate,
    ts as TradeTime,
    round(prices, 2) as TradePrice,
    int(volumes) as TradeVolume
)

// 3. Insert the data
trades.tick.append!(t)

// 4. Query the tick table
raw = select TradeTime, TradePrice
      from trades.tick
      where SecurityID = `600519.SH
        and TradeDate = 2026.06.02
      order by TradeTime

// 5. Apply a 5th-order equal-weight FIR low-pass filter
b = take(1.0 / 5, 5)

result = select
             TradeTime,
             TradePrice as rawPrice,
             fir(TradePrice, b) as filteredPrice
         from raw

select top 10 * from result

Related Functions: iir