
Financial datasets are fundamentally time-series data, making execution speed and temporal memory alignment critical. This is especially true when working with Polars Finance Indicators, which require efficient processing and fast calculations. While traditional Python frameworks struggle with rolling calculations due to single-threaded overhead, Polars handles time-series analysis at bare-metal speeds.
By utilizing localized expressions and multi-threaded execution pools, Polars can calculate complex quantitative indicators over millions of rows in milliseconds.
Let’s calculate two common trading indicators:
- SMA (Simple Moving Average): The average price over the last N days.
- RSI (Relative Strength Index): A momentum indicator.
The Setup
import polars as pl
# Dummy stock data
df = pl.DataFrame({
"date": ["2025-01-01", "2025-01-02", "2025-01-03", "2025-01-04", "2025-01-05"],
"close": [100.0, 102.0, 101.0, 105.0, 110.0]
})1. Calculating SMA (Optimized Rolling Engine)
The Simple Moving Average simply extracts the mean value of an asset over a moving window of $N$ periods. Instead of using generic .rolling() iterators, Polars exposes highly optimized, explicit native methods like .rolling_mean().
df_sma = df.with_columns(
pl.col("close")
.rolling_mean(window_size=3) # 3-period SMA execution
.alias("SMA_3")
)
print(df_sma)Output:
shape: (5, 3) โโโโโโโโโโโโโโฌโโโโโโโโฌโโโโโโโโโโโ โ date โ close โ SMA_3 โ โ --- โ --- โ --- โ โ str โ f64 โ f64 โ โโโโโโโโโโโโโโชโโโโโโโโชโโโโโโโโโโโก โ 2025-01-01 โ 100.0 โ null โ โ 2025-01-02 โ 102.0 โ null โ โ 2025-01-03 โ 101.0 โ 101.0 โ โ 2025-01-04 โ 105.0 โ 102.6667 โ โ 2025-01-05 โ 110.0 โ 105.3333 โ โโโโโโโโโโโโโโดโโโโโโโโดโโโโโโโโโโโ
2. Calculating RSI (Complex Logic)
RSI is harder. It requires calculating Gains vs. Losses. In Pandas, this is slow. In Polars, we chain expressions.
# RSI Calculation logic:
# 1. Calculate daily change (diff)
# 2. Separate into Gains (positive) and Losses (absolute value of negative)
# 3. Calculate rolling average of Gains and Losses
# 4. RSI = 100 - (100 / (1 + RS))
rsi_window = 14
df_rsi = df.with_columns(
pl.col("close").diff().alias("change")
).with_columns(
# Create Gain/Loss columns using 'when/then'
pl.when(pl.col("change") > 0).then(pl.col("change")).otherwise(0).alias("gain"),
pl.when(pl.col("change") < 0).then(pl.col("change").abs()).otherwise(0).alias("loss")
).with_columns(
# Calculate averages
pl.col("gain").rolling_mean(rsi_window).alias("avg_gain"),
pl.col("loss").rolling_mean(rsi_window).alias("avg_loss")
).with_columns(
# Final RSI Formula
(100 - (100 / (1 + (pl.col("avg_gain") / pl.col("avg_loss"))))).alias("RSI")
)This runs in parallel on millions of rows instantly.
Key Takeaways
- Financial data analysis benefits from using Polars, especially for time-series data.
- The article explains how to calculate two key trading indicators: SMA and RSI.
- SMA is computed as a rolling mean over N days using the .rolling() function.
- Calculating RSI involves complex logic, comparing Gains and Losses, and Polars executes this efficiently with chained expressions.
- Polars processes millions of rows in parallel, making it faster than Pandas.





