Repository navigation
Releases
trendfollowing v1.4.0
Changed
- Dropped Python 3.10 support; the minimum supported Python version is now 3.11.
- Required patched Pillow >= 13.0.0 for every supported interpreter and removed the
Python 3.10 lockfile fallback to Pillow 12.3.0. - Updated the CI matrix, minimum-dependency job and installation documentation for
Python 3.11+, and removed the obsolete test/docs TOML parser compatibility dependency.
Fixed
- Updated the locked certifi dependency to 2026.10.19 to address its reported vulnerability.
Installation
python -m pip install --upgrade "trendfollowing==1.4.0"Requires Python 3.11+ and Pillow 13.0.0+.
trendfollowing v1.3.0
What's Changed
- Add automatic Desktop checks and protect main with required CI by @ArturSepp in #15
- Remove the JOIM paper's tests and references by @ArturSepp in #16
- Add the trendfollowing handbook to the documentation by @ArturSepp in #17
- Release trendfollowing 1.3.0 by @ArturSepp in #18
Full Changelog: v1.2.0...v1.3.0
trendfollowing 1.1.0
trendfollowing 1.1.0
This non-breaking adoption release makes the package easier to install, discover, verify, and
use outside a source checkout.
Highlights:
- migrated the installable package to a standard
src/layout; - bundled the immutable futures dataset in wheels and source distributions;
- added deterministic root examples and task-oriented documentation;
- aligned package, citation, README, runtime, and documentation metadata;
- added clean-wheel, deployed-documentation, resource, and version-contract checks; and
- brought package code, tests, and examples under the declared Ruff E/F/W gate.
The full test matrix, independent numerical replication checks, warning-as-error documentation
build, artifact inspection, and clean wheel/sdist installs passed before publication. Numerical
results and public call signatures are unchanged.
See the changelog
and documentation.
v1.0.5
Fixed
- Every
axis=1pd.concatintrendfollowingand inpapers/statessort=explicitly — 62 call sites, 43sort=Truewhere the joined index is dates and 19sort=Falsewhere it is a lag, a span, a Monte-Carlo path or a fund label. pandas 2.2 sorted the union of two DatetimeIndexes whatever the argument said; pandas 3.0 honours an explicitsort=Falseand pandas 4 drops the implicit sort too. The exposure is the same in both trees: a backtest nav joined to a benchmark on a different calendar (backtests.py,backtest_figs.py,paper_figures.py) would be built on an out-of-order time axis, with no exception — a different number in a published exhibit. Behaviour under the installed pandas is unchanged; the arguments state what was already happening.
Added
tests/test_concat_sort_convention.py: anaxis=1pd.concatundertrendfollowing/orpapers/without an explicitsort=fails the suite. Static — reads the source withastand imports nothing.
Full changelog: CHANGELOG.md
trendfollowing 1.0.4
Portfolio-level volatility targeting in the European system produced undefined
leverage on days of non-positive portfolio variance, and this release is the first
to carry the fix. np.reciprocal(..., where=portfolio_var > 0.0) was called
without out=, so the cells the mask skips were left holding whatever the freshly
allocated buffer contained rather than zero. run_european_tf_system with
portfolio_covar_span set could therefore apply arbitrary leverage on those days,
and the value was not reproducible between runs. The fix (4b6e39a, 2026-07-22)
allocates a zero array and passes it as out=, so a non-positive-variance day
gets zero leverage. Any European-system result produced with portfolio_covar_span
set on a version at or below 1.0.3 should be regenerated.
trendfollowing/systems/american.py and trendfollowing/systems/tsmom.py still
call np.reciprocal the same way. Those two lines are unchanged in this release
and are the open item behind it.
1.0.3 was published without a changelog entry; it was a version bump in
pyproject.toml and nothing else (ff28a8a).
Added
tests/test_version_metadata.py:pyproject.toml,CITATION.cffand the
@softwareBibTeX entry inREADME.mdmust carry the same version, and
date-releasedmust be an ISO date. The three had drifted — see below.- A version-carrying
@softwareBibTeX entry inREADME.md. The README cited the
paper and nothing else, so a replication had no way to record which version of
the code it ran; for a replication package that is the citation that matters.
Fixed
CITATION.cffsaid 1.0.0 against a published 1.0.3, so anyone citing the package
from that file named a release three patches behind the code that produced the
paper's tables. It now says 1.0.4 with a currentdate-released, and the new test
fails if it drifts again.
Changed
numpyfloor raised to>=2.0, matching the rest of the stack. No resolution
changes:qisalready requires it, so every install has resolved numpy 2.x
regardless of what this file declared.- ruff no longer selects
I. Import order here groups the scientific stack before
the project packages, which isort's ordering contradicts; the rule was selected in
this repository and in no other of the stack. AGENTS.mdrecords the top-leveltests/layout as a deliberate
replication-package deviation rather than a drift from the in-package convention
the siblings use.
Removed
.coverageandexample_ar1_knife_edge.pngare no longer tracked. Both are
generated: the PNG is written into the working directory by
examples/analytic_sharpe_vs_span.py, and nothing in the README or the papers
tree references it..gitignorenow covers.coverage*andexample_*.png.
trendfollowing 1.0.3
Internal cleanup; no public API or numerical change.
Changed
universe.generate_datano longer passes the unusedcredit_dfargument when persisting the packaged dataset, and a commented-out@qis.timerdecorator onload_datais removed. No public signature changes; the packaged data are unaffected.
Notes
- Install:
pip install trendfollowing==1.0.3 - Full history in CHANGELOG.md.
trendfollowing 1.0.2
Internal cleanup; no public API or numerical change.
Changed
universe.generate_datano longer passes the unusedcredit_dfargument when persisting the packaged dataset, and a commented-out@qis.timerdecorator onload_datais removed. No public signature changes; the packaged data are unaffected.
Notes
- Install:
pip install trendfollowing==1.0.2 - Full history in CHANGELOG.md.
trendfollowing 1.0.1
Centralises the return conventions shared by the two trend-following papers into a single module, and fixes paper typos. First tagged release.
Added
trendfollowing.conventions: the single source for the conventions both papers fix. ExportsAF_DAILY = 260(the paper's trading-day annualisation, used in place of the 252 thatqisinfers from the calendar density of the futures panel, so the papers pass the constant explicitly rather than relying on inference),PPY_QUARTERLY = 4,PPY_MONTHLY = 12andcompute_daily_annualised_vol. Sharpe ratios are arithmetic throughout —sqrt(a) * mean / stdof periodic simple excess returns — because the JOIM paper's regime decomposition (Proposition 1) is exact only under arithmetic means and the SIFIN paper's analytic Sharpe ratios use the same convention. All four symbols are re-exported from the package top level.
Changed
- Replication scripts (
aggregated_skewness_fig.py,sg_sharpe_test.py,verify_skewness_directions.py) now take their annualisation and Sharpe convention fromtrendfollowing.conventionsinstead of restating it locally. - Daily futures data are stored as prices built from log returns; returns are extracted with
qis.to_returnswith theis_log_returnsflag stated at the call, and periodic returns for regime sampling are arithmetic simple returns at calendar anchors.
Fixed
- Typos in the SIFIN paper source; removed a stray
sg.logand a generated.thmfile from the repository.
Notes
- Install:
pip install trendfollowing==1.0.1 - No prior tags exist; this is the first tagged release, superseding 1.0.0 on PyPI.