Release Notes
These docs track package version 1.1.4.
1.1.0-audit (2026-03-28)
Comprehensive audit: 90 findings addressed
Code quality & correctness
Welford’s algorithm for BBANDS: replaced naive
sum_sq/N - mean^2variance with numerically stable Welford’s rolling algorithm in both batch and streaming BBANDS. Fixes catastrophic cancellation for large-valued series (e.g., prices near 1e12).FFI boundary safety:
transpose_to_series_major()inbatch/mod.rsnow returnsPyResultinstead of usingexpect(). Remainingas_slice().expect()calls inallow_threadsclosures are documented with SAFETY comments (structurally infallible after C-contiguous transpose).Clippy clean: resolved all clippy warnings — complex type in
adx_allextracted toAdxAllResulttype alias;welford_stephelper annotated with#[allow(clippy::too_many_arguments)].
Performance
``target-cpu=native``: new
.cargo/config.tomlenables native CPU instruction set (AVX2, NEON, etc.) for all non-WASM targets. CI can override viaRUSTFLAGS.
Testing
Streaming unit tests: 37 new tests in
tests/unit/streaming/test_streaming.pycoveringStreamingSMA,StreamingEMA,StreamingRSI— batch parity, warmup NaN behavior, reset, edge cases, and large dataset numerical stability.Edge case tests: 31 new tests in
tests/unit/test_edge_cases.py— empty arrays, single elements, all-NaN input, NaN propagation, extreme values (1e300, 1e-300), constant series, period boundary conditions, OHLCV edge cases, and dtype coercion (float32, int64).Property-based tests: expanded Hypothesis tests for EMA, BBANDS, MACD, ATR, WMA, and OBV with algebraic invariants (upper >= middle >= lower, histogram == macd - signal, ATR non-negative, etc.).
Pandas/polars integration tests: new
test_dataframe_integration.pyverifying transparentpd.Seriesandpolars.Seriessupport across SMA, EMA, RSI, BBANDS, MACD, and end-to-end DataFrame workflows.Fuzzing: expanded from 2 to 9 fuzz targets — added EMA, BBANDS, MACD, ATR, STOCH, MFI, and WMA with output invariant assertions.
Test helpers: new
tests/unit/helpers.pyconsolidating duplicated assertion patterns (nan_count,finite,assert_nan_warmup,assert_output_length,assert_range,make_ohlcv).
Documentation
README benchmarks: updated to match actual artifact data — MFI 3.25x, WMA 2.20x, BBANDS 1.97x, SMA 1.93x; corrected win count from 6 to 7 at 100k bars.
Rust doc comments: added comprehensive
///documentation to all public functions inferro_ta_core— overlap (SMA, EMA, WMA, BBANDS, MACD), momentum (RSI, STOCH, ADX family), volatility (ATR, TRANGE), volume (OBV, MFI), statistic (STDDEV), and math (sum, max, min, sliding_max, sliding_min).
Linting
Ruff clean: fixed import sorting, unused imports, trailing whitespace, and formatting across all Python files.
cargo fmt: all Rust code formatted.
1.1.0 (2026-03-28)
Phase 1 — Simulation fidelity
Bid-ask spread model: new
CommissionModel.spread_bpsfield (basis points). Half-spread is deducted per leg (entry and exit), modelling real market microstructure costs.Breakeven stop: new
backtest_ohlcv_coreparameterbreakeven_pctandBacktestEngine.with_breakeven_stop(pct). Once profit reachespct, the effective stop-loss is moved to the entry price, guaranteeing at worst a breakeven exit.Bracket order priority: when both stop-loss and take-profit are breached on the same bar, the level closer to the bar’s open price fires first (previously SL always won).
Phase 2 — Portfolio & risk
Short borrow cost: new
CommissionModel.short_borrow_rate_annualfield. Accrued per bar for short positions at the specified annualised rate.Leverage / margin modeling: new
BacktestEngine.with_leverage(margin_ratio, margin_call_pct). Tracks margin usage and triggers a margin-call force-close when equity falls belowmargin_call_pct × initial_margin.Loss circuit breakers: new
BacktestEngine.with_loss_limits(daily, total). Halts all trading when a per-bar loss or total drawdown threshold is breached.Portfolio constraints: new
BacktestEngine.with_portfolio_constraints(max_asset_weight, max_gross_exposure, max_net_exposure)for multi-asset backtests.
Phase 3 — Data & UX
Bar aggregation (
ferro_ta.analysis.resample):resample_ohlcv(),align_to_coarse(),resample_ohlcv_labels()— pure-NumPy OHLCV resampling from any fine TF to any coarser TF.Multi-timeframe engine (
ferro_ta.analysis.multitf):MultiTimeframeEngine— compute strategy signals on coarser bars and execute on finer bars, with automatic signal alignment.Dividend/split adjustment (
ferro_ta.analysis.adjust):adjust_ohlcv(),adjust_for_splits(),adjust_for_dividends()— backward-adjusted price series for equity/index strategies.Visualization (
ferro_ta.analysis.plot):plot_backtest()— interactive Plotly chart with equity curve, drawdown panel, position panel, trade markers, and optional benchmark overlay.
Phase 4 — Differentiation
Regime detection (
ferro_ta.analysis.regime):detect_volatility_regime(),detect_trend_regime(),detect_combined_regime(),RegimeFilter— pure-NumPy 6-state market regime labeling and signal filtering; no external ML dependencies.Portfolio optimization (
ferro_ta.analysis.optimize):PortfolioOptimizer,mean_variance_optimize(),risk_parity_optimize(),max_sharpe_optimize()— minimum-variance, risk-parity, and maximum-Sharpe portfolios via SLSQP (requires scipy).Paper trading bridge (
ferro_ta.analysis.live):PaperTrader— event-driven bar-by-bar simulator matchingbacktest_ohlcv_corelogic exactly; supports streaming data, live state inspection, and seamless strategy migration from backtesting to live.
1.1.0 (2026-03-27)
Advanced commission and fee model (Indian market support)
New
CommissionModelclass (pure Rust inferro_ta_core, exposed via PyO3 and WASM) replaces the broken flatcommission_per_tradescalar. The old code subtracted an absolute currency amount from a 1.0-normalised equity curve — equivalent to a 2 000 % error on a ₹1 lakh account. The new model correctly converts every charge to a fraction ofinitial_capitalbefore deducting it from the equity curve.CommissionModelsupports: proportional brokerage (rate_of_value), flat per-order fee (flat_per_order), per-lot fee (per_lot), brokerage cap (max_brokerage), Securities Transaction Tax (stt_ratewith configurable buy/sell sides), exchange transaction charges, SEBI regulatory charges, 18 % GST on brokerage + exchange + regulatory levies, and stamp duty on buy leg only.Built-in presets:
CommissionModel.equity_delivery_india(),CommissionModel.equity_intraday_india(),CommissionModel.futures_india(),CommissionModel.options_india(),CommissionModel.proportional(rate),CommissionModel.zero().JSON persistence:
model.to_json()/CommissionModel.from_json(s),model.save(path)/CommissionModel.load(path).BacktestEngine.with_commission_model(model)— pass a fullCommissionModel; oldwith_commission(rate)kept as a shim.New
initial_capitalparameter (default ₹1,00,000) on bothbacktest_coreandbacktest_ohlcv_core; also exposed asBacktestEngine.with_initial_capital(capital).
Currency system — INR default with lakh/crore formatting
New
Currencyimmutable descriptor in the Python layer with constantsINR,USD,EUR,GBP,JPY,USDT.INRis the default currency forBacktestEngine; change viaengine.with_currency("USD")orengine.with_currency(EUR).currency.format(amount)produces Indian lakh/crore grouping for INR (e.g.₹1,23,45,678.00) and standard Western grouping for other currencies.Module-level helper
format_currency(amount, currency=INR).AdvancedBacktestResultgainscurrency,initial_capital, andequity_abs(absolute currency equity curve) slots.summary()now includesinitial_capital,final_capital,absolute_pnl, andcurrencykeys.AdvancedBacktestResult.__repr__shows the final capital in the correct currency symbol (e.g.final=₹1,23,450.00).Trade log gains a
pnl_abscolumn (PnL in absolute currency units).to_equity_dataframe()now includes anequity_abscolumn.
Trailing stop loss
backtest_ohlcv_core(andBacktestEngine.with_trailing_stop(pct)) now supports a trailing stop implemented intrabar in Rust: the high-water mark is updated each bar; the position is exited attrail_high × (1 − pct)whenlow[i]crosses below it (long trades), ortrail_low × (1 + pct)for short trades.
Benchmark comparison metrics
compute_performance_metricsaccepts an optionalbenchmark_returnsarray. When provided,summary()includes:benchmark_total_return,benchmark_cagr,benchmark_annualized_vol,benchmark_sharpe,alpha(active return),beta,tracking_error, andinformation_ratio.BacktestEngine.with_benchmark(close_array)— pass benchmark close prices.
Volatility-target position sizing
New
"volatility_target"method forwith_position_sizing():engine.with_position_sizing("volatility_target", target_vol=0.15, vol_window=20). Signals are pre-scaled in Python byclip(target_vol / rolling_annualised_vol, 0, 3)before the Rust core call, keeping the hot loop unchanged.
Backtesting engine v2 — full feature set
BacktestEnginenow supports true two-pass Kelly / half-Kelly position sizing: a unit-signal pass computes win statistics, then the core engine re-runs with signals scaled by the Kelly fraction.Added
fixed_fractionalposition sizing method:engine.with_position_sizing("fixed_fractional", fraction=0.5).New
StreamingBacktestRust class for bar-by-bar incremental backtesting (no bulk arrays needed); exposes.on_bar(),.summary(),.reset().AdvancedBacktestResult.to_equity_dataframe(freq)— returns equity, returns, and drawdown as apd.DataFramewith a synthetic DatetimeIndex.AdvancedBacktestResult.summary()— concise dict of the 9 most commonly cited metrics plusn_trades.
Core indicator speedup
ADX-family indicators (
adx_allpublic API): all six series (PDM, MDM, +DI, -DI, DX, ADX) can now be computed from a single TR/PDM/MDM pass viaferro_ta.adx_all(), eliminating the 6× redundant computation that occurred when callers fetched each series independently.adxrnow reuses a singleadx_innercall internally (was callingadx()which re-ran the inner loop).
1.0.6 (2026-03-24)
Added a repo-managed pre-push gate so the core Rust, Python, docs, and WASM checks can be run locally before release.
Expanded Rust-backed analysis/data helpers, broadened the WASM exports, and added cross-surface API manifest verification plus Node conformance checks.
Refreshed benchmark coverage and perf artifacts, aligned Python CI with the local tooling flow, and updated the locked security fixes needed for a clean release pass.
1.0.4 (2026-03-24)
Expanded the optional MCP server from a small hand-written subset to the broader public ferro-ta callable surface, including stateful class support through stored-instance management tools.
Split the root documentation so the full TA-Lib compatibility matrix lives in
TA_LIB_COMPATIBILITY.mdwhile the README stays product-first and shorter.Refreshed MCP docs/tests and updated locked low-risk Python dependencies as part of the release cleanup pass.
Stopped tracking the stray
.coverageartifact and aligned ignore rules for local coverage outputs.
1.0.3 (2026-03-24)
Added top-level package metadata helpers such as
ferro_ta.__version__,ferro_ta.about(), andferro_ta.methods().Added a standalone derivatives benchmark artifact for selected options pricing, IV, Greeks, and Black-76 comparisons.
Simplified release version bumps with a single script and updated release guidance.
Fixed Python CI/type-stub gaps around the new metadata API and corrected the tag-driven GitHub Release workflow trigger used for publish automation.
1.0.2 (2026-03-24)
Improved rolling statistical kernels and several Python analysis hotspots.
Added reproducible perf-contract artifacts, TA-Lib regression guards, and updated benchmark tooling.
Tightened the public benchmark documentation so claims, caveats, and evidence live closer together.
1.0.1 (2026-03-24)
Improved release automation for PyPI, crates.io, and npm.
Fixed CI workflow issues that caused otherwise healthy release jobs to fail.
Ensured the published WASM package includes its built
pkg/artifacts.
1.0.0 (2026-03-23)
First stable release of the Rust-backed Python technical analysis library.
Shipped broad TA-Lib coverage, streaming APIs, extended indicators, and the initial Sphinx documentation set.
Added the benchmark suite, release playbook, and compatibility/testing scaffolding for stable releases.
For the canonical project changelog, including the full per-version details, see CHANGELOG.md.