API¶
Tick Expressions¶
Activity¶
calc_burstiness(self, per='s')
¶
Calculates burstiness as std(inter-trade time) / mean(inter-trade time).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
timestamp column |
required |
per
|
str
|
time unit ("s", "ms", "us", "ns") |
's'
|
Returns:
| Type | Description |
|---|---|
Expr
|
Float representing burstiness of trading activity. |
Source code in ffn_polars/expr/tick/activity.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | |
calc_inter_trade_time(self, per='s')
¶
Calculates the average time between consecutive trades.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
Timestamp column |
required |
per
|
str
|
Time unit — "s", "ms", "us", or "ns" |
's'
|
Returns:
| Type | Description |
|---|---|
Expr
|
Float expression representing mean inter-trade time in desired unit |
Example
df.group_by("ticker").agg( pl.col("timestamp").calc_inter_trade_time(per="ms") )
Source code in ffn_polars/expr/tick/activity.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
calc_trade_rate(self, per='ms')
¶
Calculates trade rate as number of trades per second.
Assumes self is a timestamp column from tick data.
Returns:
| Type | Description |
|---|---|
Expr
|
An expression representing trades per second: |
Expr
|
(count of rows) / (max(timestamp) - min(timestamp)).seconds |
Example
df.group_by("ticker").agg( pl.col("timestamp").calc_trade_rate() )
Source code in ffn_polars/expr/tick/activity.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
Bars¶
Direction¶
apply_tick_rule_to_volume(self, price)
¶
Applies the tick rule to volume data. Args: self: Volume column price: Price column Returns: Volume with sign based on tick rule
Source code in ffn_polars/expr/tick/direction.py
26 27 28 29 30 31 32 33 34 35 36 37 38 | |
calc_tick_imbalance(self)
¶
Calculates tick imbalance using signed volume.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
signed tick rule / direction column |
required |
Returns:
| Type | Description |
|---|---|
Expr
|
Float between -1 and 1 |
Source code in ffn_polars/expr/tick/direction.py
41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
tick_rule(self)
¶
Infers trade direction using the tick rule
+1 if price > prev_price -1 if price < prev_price 0 otherwise
Source code in ffn_polars/expr/tick/direction.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
Flow¶
calc_order_flow_imbalance(self)
¶
Calculates Order Flow Imbalance (OFI) as the sum of signed volume.
Assumes volume is signed
+V = buyer-initiated -V = seller-initiated
Returns:
| Type | Description |
|---|---|
Expr
|
Float (positive = net buying, negative = net selling) |
Example
df.group_by("ticker").agg( pl.col("signed_volume").calc_order_flow_imbalance() )
Source code in ffn_polars/expr/tick/flow.py
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 | |
calc_traded_value(self, volume)
¶
Calculates traded value (price × volume sum).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
Float column of trade prices |
required |
volume
|
ExprOrStr
|
Numeric column of trade volumes |
required |
Returns:
| Name | Type | Description |
|---|---|---|
Float |
Expr
|
total traded value (dollar volume) |
Example
df.group_by("ticker").agg( calc_traded_value("price", "volume") )
Source code in ffn_polars/expr/tick/flow.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 | |
calc_volume_rate(self, ts, per='s')
¶
Calculates volume traded per unit time.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
Numeric column of trade volumes |
required |
ts
|
ExprOrStr
|
Datetime column |
required |
per
|
str
|
"s", "ms", "us", or "ns" (default "s") |
's'
|
Returns:
| Type | Description |
|---|---|
Expr
|
Float expression representing volume per unit time |
Example
df.group_by("ticker").agg( calc_volume_rate("volume", "timestamp", per="ms") )
Source code in ffn_polars/expr/tick/flow.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | |
calc_vwap(self, volume)
¶
Calculates volume-weighted average price (VWAP).
Formula
VWAP = sum(price * volume) / sum(volume)
Returns:
| Type | Description |
|---|---|
Expr
|
A float expression representing VWAP |
Example
df.group_by("ticker").agg( calc_vwap("price", "volume") )
Source code in ffn_polars/expr/tick/flow.py
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
Latency¶
Price¶
calc_micro_returns(self)
¶
Calculates log returns at tick level
log(p_t) - log(p_{t-1})
Returns:
| Type | Description |
|---|---|
Expr
|
Tick-level log return series |
Source code in ffn_polars/expr/tick/price.py
7 8 9 10 11 12 13 14 15 16 17 18 | |
calc_price_impact(self, volume)
¶
Calculates absolute price impact
(last price - first price) / sum(volume)
Assumes volume is unsigned and price is a float column.
Returns:
| Type | Description |
|---|---|
Expr
|
Float representing absolute price impact per unit volume |
Example
df.group_by("ticker").agg( calc_price_impact("price", "volume") )
Source code in ffn_polars/expr/tick/price.py
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
calc_price_volatility_ratio(self)
¶
Computes the coefficient of variation
std(price) / mean(price)
Returns:
| Name | Type | Description |
|---|---|---|
Float |
Expr
|
unitless relative volatility |
Source code in ffn_polars/expr/tick/price.py
21 22 23 24 25 26 27 28 29 30 31 32 | |
Volatility¶
calc_realized_volatility(self)
¶
Calculates realized volatility (non-annualized) from a price series.
Formula
sqrt(Σ (log(p_t) - log(p_{t-1}))^2)
Assumes self is a price series. Use inside .select() or .group_by().agg().
Returns:
| Type | Description |
|---|---|
Expr
|
Realized volatility over the window |
Example
df.group_by("ticker").agg( pl.col("price").calc_realized_volatility() )
Source code in ffn_polars/expr/tick/volatility.py
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
EOD Expressions¶
Ratios¶
calc_calmar_ratio(self, date_col)
¶
Returns a Polars expression to compute the Calmar ratio: CAGR / |Max Drawdown|
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
Column name of price series |
required |
date_col
|
str
|
Column name of date series |
required |
Returns:
| Type | Description |
|---|---|
Expr
|
pl.Expr: Calmar ratio expression |
Source code in ffn_polars/expr/eod/ratios.py
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | |
calc_information_ratio(self, benchmark)
¶
Returns a Polars expression that computes the Information Ratio.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
name of the column with asset returns |
required |
benchmark
|
ExprOrStr
|
name of the column with benchmark returns |
required |
Source code in ffn_polars/expr/eod/ratios.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | |
calc_prob_mom(self, b)
¶
Polars expression that computes probabilistic momentum between two return columns. If Rust plugin is available, uses it. Otherwise, falls back to a Polars map_batches version.
Source code in ffn_polars/expr/eod/ratios.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 | |
calc_risk_return_ratio(self)
¶
Calculates the return / risk ratio. Basically the
Sharpe ratio <https://www.investopedia.com/terms/s/sharperatio.asp> without factoring in the risk-free rate <https://www.investopedia.com/terms/r/risk-freerate.asp>.
Source code in ffn_polars/expr/eod/ratios.py
89 90 91 92 93 94 95 96 97 | |
calc_sharpe(self, rf=0.0, n=252, annualize=True)
¶
Polars expression that computes the Sharpe ratio in-place without aliasing.
Source code in ffn_polars/expr/eod/ratios.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | |
Returns¶
calc_cagr(self, date_col)
¶
Calculates the CAGR (compound annual growth rate) <https://www.investopedia.com/terms/c/cagr.asp>_ for a given price series.
Returns:
| Type | Description |
|---|---|
Expr
|
|
Source code in ffn_polars/expr/eod/returns.py
92 93 94 95 96 97 98 99 100 101 102 103 104 | |
calc_mtd(self, date_col='Date')
¶
Calculate Month-To-Date return using daily prices only.
Logic: - Latest price = last row - Reference price = last price from previous month - MTD = (latest / reference) - 1
Source code in ffn_polars/expr/eod/returns.py
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | |
calc_total_return(self)
¶
Calculates the total return of a series.
last / first - 1
Source code in ffn_polars/expr/eod/returns.py
152 153 154 155 156 157 158 159 160 161 | |
calc_ytd(self, date_col='Date')
¶
Calculate Year-To-Date (YTD) return using daily prices.
Logic: - Identify current year from latest date - First price = first row of current year - Latest price = most recent row - YTD = (latest / first_of_year) - 1
Assumes date_col is sorted ascending.
Source code in ffn_polars/expr/eod/returns.py
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 | |
rebase(self, value=100)
¶
Rebase a price series to a given value.
Formula is: (p / p0) * value
Source code in ffn_polars/expr/eod/returns.py
140 141 142 143 144 145 146 147 148 149 | |
to_excess_returns(self, rf, n)
¶
Returns a Polars expression that computes excess returns.
Source code in ffn_polars/expr/eod/returns.py
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 | |
to_log_returns(self)
¶
Calculates the log returns of a price series.
Formula is: ln(p1/p0)
Source code in ffn_polars/expr/eod/returns.py
24 25 26 27 28 29 30 31 32 33 34 | |
to_price_index(self, start=100)
¶
Returns a price index given a series of returns.
Assumes arithmetic returns.
Formula is: cumprod (1+r)
Source code in ffn_polars/expr/eod/returns.py
126 127 128 129 130 131 132 133 134 135 136 137 | |
to_returns(self)
¶
Calculates the simple arithmetic returns of a price series.
Formula is: (t1 / t0) - 1
Source code in ffn_polars/expr/eod/returns.py
11 12 13 14 15 16 17 18 19 20 21 | |
Risk¶
calc_max_drawdown(self)
¶
Calculates the max drawdown of a price series. If you want the actual drawdown series, please use to_drawdown_series.
Source code in ffn_polars/expr/eod/risk.py
89 90 91 92 93 94 95 96 97 | |
to_drawdown_series(self)
¶
Calculates the drawdown <https://www.investopedia.com/terms/d/drawdown.asp>_ series.
This returns a series representing a drawdown. When the price is at all time highs, the drawdown is 0. However, when prices are below high water marks, the drawdown series = current / hwm - 1
The max drawdown can be obtained by simply calling .min() on the result (since the drawdown series is negative)
Method ignores all gaps of NaN's in the price series.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
prices |
required |
Source code in ffn_polars/expr/eod/risk.py
63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | |
ulcer_index(self)
¶
Returns a Polars expression to compute the Ulcer Index from a price series.
Formula
- Compute cumulative max of prices.
- Calculate drawdowns: ((price - cummax) / cummax) * 100.
- Square drawdowns, take mean, then square root.
Source code in ffn_polars/expr/eod/risk.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | |
ulcer_performance_index(self, rf=0.0, n=None)
¶
Returns a Polars expression to compute Ulcer Performance Index (UPI).
UPI = mean(excess returns) / ulcer index
Must be used inside .select() or .with_columns()
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
column with prices |
required |
rf
|
Union[float, str]
|
either a float (annualized) or a column name containing RF series |
0.0
|
n
|
int
|
required if rf is float and nonzero |
None
|
Source code in ffn_polars/expr/eod/risk.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | |
Temporal¶
annualize(self, durations, one_year=365.0)
¶
Returns a Polars expression to annualize returns given durations.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
Name of the column with returns (e.g., 0.05 = 5%). |
required |
durations
|
ExprOrStr
|
Name of the column with durations (e.g., days held). |
required |
one_year
|
float
|
Number of periods in a year (default 365.0 for days). |
365.0
|
Returns:
| Type | Description |
|---|---|
Expr
|
pl.Expr: Expression computing annualized return. |
Source code in ffn_polars/expr/eod/temporal.py
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | |
deannualize(self, n)
¶
Returns a Polars expression that converts annualized returns to periodic returns.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
self
|
ExprOrStr
|
column containing annualized returns |
required |
n
|
int
|
Number of periods per year (e.g., 252 for daily) |
required |
Source code in ffn_polars/expr/eod/temporal.py
13 14 15 16 17 18 19 20 21 22 23 24 | |
infer_freq(self)
¶
Infers human-readable calendar frequency label from a datetime column. Works best for: yearly, quarterly, monthly, weekly, daily.
Returns: "yearly", "quarterly", "monthly", "weekly", "daily", or None
Source code in ffn_polars/expr/eod/temporal.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | |
year_frac(self)
¶
Returns a Polars expression that computes the year fraction between the first and last date in a column, assuming average year length (365.25 days = 31557600 seconds).
Source code in ffn_polars/expr/eod/temporal.py
158 159 160 161 162 163 164 165 166 167 168 | |