Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

Finalytics

PyPI Python 3.10+ Downloads CI Licence Homepage

Finalytics is a portfolio analytics engine written in Rust, with this typed Python package over it. It compares portfolio optimisation methods on returns they have not seen, keeps the books of a real portfolio to report its performance, risk and attribution, tests a plan's chance of meeting a goal, and screens thousands of securities by rules on their measures.

pip install "finalytics[pandas]"  # with pandas, as the examples below use
pip install finalytics            # with NumPy only

Without pandas, the datasets come as price tables, which Assets takes as well: fl.Assets(fl.datasets.asset_class_table(), risk_free_asset="T-Bills").

Until 1.0.0 is released, pip install finalytics gives 0.9; install a 1.0 pre-release with pip install --pre finalytics. The migration guide explains what replaces each part of 0.9.

Sample reports, built by the programs below from the bundled datasets and, for screening, the S&P 500 prices in tests/sp500: comparison · backtest · optimisation · portfolio · rebalance · planning · screening

Portfolio optimisation

Compare optimisation methods on the same assets. Each method is refitted every quarter on the five years before, and judged on the quarter that follows.

import finalytics as fl

assets = fl.Assets(fl.datasets.asset_class_prices(), risk_free_asset="T-Bills")

result = assets.compare(
    methods=[
        "equal_weight",
        "minimum_variance",
        "maximum_sharpe",
        "maximum_diversification",
        "risk_parity",
        "hierarchical_risk_parity",
    ],
    max_weight=0.40,
    rebalance="quarterly",
    validation=fl.WalkForward(years=5),
    trading_cost_bps=10,
)

result.show()

The comparison report: each method's return, volatility, Sharpe ratio, drawdown and turnover out of sample

Every result has the same shape: result.report is the report, which print(result) prints as text and result.show() opens as a page (inline in a Jupyter notebook), and result.results holds every return and trade behind it. A program that shows pages itself, such as a web page running Python with Pyodide, hands show() a function with fl.set_show_handler, which then receives each page's HTML.

To test one allocation, give a method or your own weights. Here, the maximum Sharpe ratio fitted to the years before November 2016, held from then on against a 60/40 benchmark:

result = assets.backtest(
    method="maximum_sharpe",
    max_weight=0.40,
    benchmark={"US Equity": 0.60, "Bonds": 0.40},
    rebalance="quarterly",
    validation=fl.Holdout(start="2016-11-01"),
)

result.show()

The backtest report: the allocation, its statistics in and out of sample against the benchmark, and its growth

To see the weights a method chooses today, where their risk comes from and where they sit on the efficient frontier:

result = assets.optimise(
    method="maximum_sharpe", max_weight=0.40, frontier=True
)

result.show()

The optimisation report: the weights, what they are expected to deliver, and each asset's share of the risk

Portfolio analytics

Load a portfolio from its transactions and prices, and report on it: holdings, performance, risk, attribution and scenarios.

import finalytics as fl

portfolio = fl.Portfolio.from_csv(
    transactions="transactions.csv",
    prices="prices.csv",
    fx="fx.csv",
    instruments="instruments.csv",
    accounts="accounts.csv",
)

report = portfolio.report(benchmark="BENCH", group_by=["asset_class", "region"])

report.show()

The portfolio report: value, returns, volatility, drawdown and value at risk, and growth against the benchmark

The files are the portfolio dataset: a household's brokerage and retirement accounts, holding five funds in dollars and euros for three years. fl.datasets.file("portfolio/prices.csv") and the like return each of them, and fl.datasets.portfolio() loads the same portfolio without them. BENCH is a column of prices.csv, the benchmark's levels; asset_class and region are columns of instruments.csv that classify each holding. The sample report adds the attribution and scenarios of fl.datasets.report_options(). A portfolio's report is its own result: every figure in it is the portfolio's, so report() returns the report, with no results beside it.

The start of the dataset's files
id,kind,currency,name,class.asset_class,class.region
VTI,fund,USD,Vanguard Total Stock Market ETF,Equity,North America
EXSA,fund,EUR,iShares STOXX Europe 600 UCITS ETF (DE),Equity,Europe
date,VTI,EXSA,BND,GLD,VNQ,BENCH
2023-11-01,208.86,43.21,68.99,183.51,73.37,100.0000
2023-11-02,213.01,43.92,69.39,184.12,75.78,101.4345
id,name,lot_method,taxable,class.owner,class.wrapper
brokerage,Brokerage account,fifo,true,Alex,Taxable
ira,Retirement account,fifo,false,Alex,Tax-deferred

The data guide describes every file, column by column.

To move the same funds to their least risky mix, 5% to 40% each, optimise the holdings and rebalance the accounts together, with fees and tax rates:

target = portfolio.assets().optimise(
    method="minimum_variance", bounds=(0.05, 0.40)
)

result = portfolio.rebalance(
    target, whole_units=True, fee_bps=5, minimum_fee=1, tax=(0.37, 0.20)
)

result.show()

The rebalance report: the trades, how each holding's weight moves, and what the trades change and cost

Sales in the brokerage account take the lots that cost the least tax; the retirement account is not taxable (taxable is false in accounts.csv), so its sales pay none. portfolio.with_rebalance(result) makes the trades.

Financial Planning

Test a plan of saving, spending and investing against one goal: an amount by a date, such as a house deposit, or payments over a period, such as an income in retirement. The plan runs month by month through 10,000 markets drawn from the assets' monthly returns, in today's money: returns are after inflation and fees.

import finalytics as fl

assets = fl.Assets(fl.datasets.asset_class_prices())

plan = assets.plan(
    fl.Payments(amount=4_000, start="2046-11", end="2076-10"),
    name="Retirement income",
    chance=0.85,
    start_value=250_000,
    flows=[fl.Saving(amount=1_500, every="month")],
    weights=("Balanced 60/40", {"US Equity": 0.60, "Bonds": 0.40}),
    alternatives={
        "Cautious 30/70": {"US Equity": 0.30, "Bonds": 0.70},
        "Growth 80/20": {"US Equity": 0.80, "Bonds": 0.20},
    },
    inflation=0.025,
    fee=0.0025,
    currency="USD",
)

plan.show()

The planning report: the plan, its chance of meeting the goal, and the money over time in simulated markets

The report gives the chance of meeting the goal against the chance wanted, how the money could grow, and the smallest change that would reach that chance: saving more, starting with more, starting the payments later or taking a little less. It tests the plan when returns are lower and when markets crash as the payments start, and compares other mixes on the same simulations. plan.results holds the figures behind it, with the value over time.

For an amount by a date, give fl.Target(amount=150_000, by="2030-06"); for a single payment out along the way, fl.Spending(name="Car", amount=25_000, on="2028-03"); and for inflation month by month, a price index of one column, such as a consumer price index, inflation=index.

Screening

Screen many securities at once, each measured on its own history: returns over calendar windows, risk, measures against a benchmark, technical indicators, income and volume. Rules test the measures and any fields given with the securities, such as a sector or a price-to-earnings ratio.

import finalytics as fl

universe = fl.Universe(
    "tests/sp500/prices.csv",
    fields="tests/sp500/companies.csv",
    risk_free_rate=0.04,
)

screen = universe.screen(
    rules=[
        ("return_1y", ">", 0.0),
        ("volatility", "<", 0.30),
        ("price_to_sma_200", ">", 1.0),
        ("rsi_14", "between", (30, 70)),
        ("max_drawdown_3y", ">", -0.30),
        ("sector", "not_in", ["Utilities"]),
    ],
    sort=("sharpe_ratio_3y", "descending"),
    limit=10,
)

screen.show()

The screening report: how the rules narrow the list, the matches in order and the near misses

The report shows how the rules narrow the list, the matches in order, the near misses and where each rule's threshold falls across the universe.

What is included

Optimisation

  • Equal weight, minimum variance, mean–variance and robust mean–variance, maximum Sharpe, target return or volatility, maximum diversification, minimum CVaR, risk parity, hierarchical risk parity
  • Limits on each asset and on groups, turnover, tracking error and factor exposure
  • Black–Litterman and resampled estimates; Ledoit–Wolf, OAS and EWMA covariance
  • Validation in sample, on a holdout, or walk-forward; calendar or drift rebalancing; trading costs

Analytics

  • Books from transactions: lots, corporate actions, several accounts and currencies
  • Time- and money-weighted returns, contribution, Brinson–Fachler and currency attribution
  • Volatility, drawdowns, value at risk, risk decomposition, factor models and scenarios
  • Rebalancing trades with fees and tax-aware lot selection, across accounts

Planning

  • The chance of a goal, an amount by a date or payments over a period, from simulated markets: block bootstrap, normal or historical
  • Saving and spending once or regularly, fixed or glide-path mixes, fees and inflation, in today's money
  • The changes that reach the chance wanted, lower returns and a crash, and other mixes on the same simulations

Screening

  • Thousands of securities, each on its own dates, with volumes, dividends and fields such as a sector or a valuation
  • Returns over calendar windows, volatility, drawdowns, Sharpe and Sortino ratios, value at risk, beta and relative returns, moving averages, RSI and MACD, dividend yield and volume
  • Rules on the measures and on the fields, sorted and limited

Every report prints as text, 80 columns wide, and shows as one self-contained HTML page, in light and dark. Every model is tested against an independent implementation; the methods pages define each one.

Beneath the front doors, fl.risk, fl.opt and fl.performance give each method on its own, and results are frozen dataclasses with documented fields (see finalytics.types). Wheels are published for Linux, macOS and Windows.

Documentation

Data guide · Methods · Performance · Migrating from 0.9 · Source and issues

Contributing and licence

Contributions are welcome: see CONTRIBUTING.md. Finalytics is licensed under MIT or Apache-2.0, at your option. It provides analysis tools only and is not investment advice.

Metadata

Release files for finalytics 1.0.0rc7

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for finalytics 1.0.0rc7
File Size Uploaded Provenance Actions
finalytics-1.0.0rc7.tar.gz 1.2 MB Without provenance Details for finalytics-1.0.0rc7.tar.gz

Built distributions (wheels)

Table of built distributions (wheels) for finalytics 1.0.0rc7
File Actions
finalytics-1.0.0rc7-cp310-abi3-win_amd64.whl CPython 3.10 abi3 Windows x86-64 Details for finalytics-1.0.0rc7-cp310-abi3-win_amd64.whl
finalytics-1.0.0rc7-cp310-abi3-musllinux_1_2_x86_64.whl CPython 3.10 abi3 Linux musl 1.2+ x86-64 Details for finalytics-1.0.0rc7-cp310-abi3-musllinux_1_2_x86_64.whl
finalytics-1.0.0rc7-cp310-abi3-musllinux_1_2_aarch64.whl CPython 3.10 abi3 Linux musl 1.2+ ARM64 Details for finalytics-1.0.0rc7-cp310-abi3-musllinux_1_2_aarch64.whl
finalytics-1.0.0rc7-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl CPython 3.10 abi3 Linux glibc 2.17+ x86-64 Details for finalytics-1.0.0rc7-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
finalytics-1.0.0rc7-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl CPython 3.10 abi3 Linux glibc 2.17+ ARM64 Details for finalytics-1.0.0rc7-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
finalytics-1.0.0rc7-cp310-abi3-macosx_11_0_arm64.whl CPython 3.10 abi3 macOS 11.0+ ARM64 Details for finalytics-1.0.0rc7-cp310-abi3-macosx_11_0_arm64.whl
finalytics-1.0.0rc7-cp310-abi3-macosx_10_12_x86_64.whl CPython 3.10 abi3 macOS 10.12+ x86-64 Details for finalytics-1.0.0rc7-cp310-abi3-macosx_10_12_x86_64.whl

Total release size: 40.3 MB

Release files / finalytics-1.0.0rc7.tar.gz

Download URL finalytics-1.0.0rc7.tar.gz
Size 1.2 MB
Tags Source
SHA-256 checksum
How to use checksums
344f051fcbcc17da800fc22906ed5d3fb8e4f1e318a58b9fcb4b4c251f9a614b
BLAKE2b-256 checksum
How to use checksums
01de31cf4e3586b6de3a2449bde4d30b74317bd9191abcf78eb8dcbcb3ff68b3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / finalytics-1.0.0rc7-cp310-abi3-win_amd64.whl

Download URL finalytics-1.0.0rc7-cp310-abi3-win_amd64.whl
Size 5.9 MB
Tags CPython 3.10 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
598b7a3d143113a6f02c2102609e7b97e3bd5faadf2363e578097aca6169cc52
BLAKE2b-256 checksum
How to use checksums
c6e2f23f7bbb78c833e597d2ce3718689ce098025cdc7bd2e5650498fc4bb53b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / finalytics-1.0.0rc7-cp310-abi3-musllinux_1_2_x86_64.whl

Download URL finalytics-1.0.0rc7-cp310-abi3-musllinux_1_2_x86_64.whl
Size 6.0 MB
Tags CPython 3.10 Linux musl 1.2+ x86-64 abi3
SHA-256 checksum
How to use checksums
2ee2ba30aeb164460681bd20eef839e6d6efba4a954f49b78fb8d54b46d27e20
BLAKE2b-256 checksum
How to use checksums
7d60d44e043fd4fe5b7ec1e1ee2516069a13c6a824e62857e55145aa2529bd94
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / finalytics-1.0.0rc7-cp310-abi3-musllinux_1_2_aarch64.whl

Download URL finalytics-1.0.0rc7-cp310-abi3-musllinux_1_2_aarch64.whl
Size 5.5 MB
Tags CPython 3.10 Linux musl 1.2+ ARM64 abi3
SHA-256 checksum
How to use checksums
4696fe1af50db58029d967497acd2f798bf31659e312a50dbe3ed91d33668e80
BLAKE2b-256 checksum
How to use checksums
5a8488352a3cbe61e65978d0245829e88f087b86accbaa00bfa2ed5aa49b57a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / finalytics-1.0.0rc7-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl

Download URL finalytics-1.0.0rc7-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl
Size 5.7 MB
Tags CPython 3.10 Linux glibc 2.17+ x86-64 abi3
SHA-256 checksum
How to use checksums
a3777ba1a46a39f2727ccc90e25e90445bcae6b4f18d081e1daa06f6df86791f
BLAKE2b-256 checksum
How to use checksums
a10d0b658400183bc21bed95bc724f49fe3c87fd0c7deeb4035d7f2bb1eb6fb5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / finalytics-1.0.0rc7-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl

Download URL finalytics-1.0.0rc7-cp310-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl
Size 5.3 MB
Tags CPython 3.10 Linux glibc 2.17+ ARM64 abi3
SHA-256 checksum
How to use checksums
01a472a9b52ee64ad8c0cfc3b8c099b89ef4c3217c8c353572384f471ef5fdf6
BLAKE2b-256 checksum
How to use checksums
d93d70346292caa2cd89901714bc918b78a33eee0dba8c9efaa7bf2d6a3a96f0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / finalytics-1.0.0rc7-cp310-abi3-macosx_11_0_arm64.whl

Download URL finalytics-1.0.0rc7-cp310-abi3-macosx_11_0_arm64.whl
Size 5.1 MB
Tags CPython 3.10 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
92ac2b6019aec6701f66db0579b1594f5bab26564952d2d8a013a96d1bee1705
BLAKE2b-256 checksum
How to use checksums
1c19ef50d324341a58878528a7d52b484475e1cd0f6eec1848c0592cc31b7b25
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Release files / finalytics-1.0.0rc7-cp310-abi3-macosx_10_12_x86_64.whl

Download URL finalytics-1.0.0rc7-cp310-abi3-macosx_10_12_x86_64.whl
Size 5.6 MB
Tags CPython 3.10 abi3 macOS 10.12+ x86-64
SHA-256 checksum
How to use checksums
3e617af4f3b1a9b026da64e7990e4e174f488b6c87b06dcf31aa683a567478a0
BLAKE2b-256 checksum
How to use checksums
f5e42e757f14baf7e85c0ae69400bcf9349aaf73a50492bc95d83c2e805bf167
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.16

Security for finalytics 1.0.0rc7

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page