V0 Changelog#

0.3.0 (2026-09-27)#

Added#

  • One licence check for every KaxaNuk library. Attribution validates its licence through kaxanuk-license-client 1.0, the package the Backtest Engine, Attribution Analysis and Portfolio Construction share, instead of a validator of its own. It is a new dependency, kaxanuk-license-client~=1.0, which takes the client’s fixes without a new attribution release, and it comes from KaxaNuk’s private package index, the one the pip install command of the welcome email names, which serves it to any valid licence. services.license_validator stays as a thin wrapper with the names attribution and the KaxaNuk Research Lab use: validate_license(), _state (now the client’s own dict, changed in place and never replaced), the licence errors as attributes of the module, and a new reset_validation_state(), which forgets that the process validated so the next call checks again. It also holds PRODUCT, what attribution tells the client about itself: the product attribution-analysis, the key in KNAA_API_KEY_KAXANUK, another server in KNAA_LICENSE_SERVER_URL, the unified licence server by default, and the logger it has always used, kaxanuk.attribution_analysis.services.license_validator. The Research Lab, which puts each user’s key in KNAA_API_KEY_KAXANUK, clears _state["validated"] before validating and catches the errors by name, keeps working as it is.

  • ``LicenseConfigurationError``, raised when KNAA_LICENSE_SERVER_URL or KAXANUK_LICENSE_SERVER_URL is not an http or https URL a request can be sent to, before anything is sent. The licence errors, LicenseError and its four subclasses, now inherit from AttributionAnalysisError and from the client’s matching error at once, so both except AttributionAnalysisError and except kaxanuk.license_client.LicenseError catch them.

  • ``KNAA_LICENSE_SERVER_URL`` points attribution, and only attribution, at another licence server. KAXANUK_LICENSE_SERVER_URL still works, for every KaxaNuk library, and is read after it.

Changed#

  • The licence is checked on the unified KaxaNuk licence server, for this product. Without a server variable, attribution validates on the licence server that serves every KaxaNuk library instead of on a server of its own, and the request names the product, attribution-analysis, and attribution’s version: a licence that does not include Attribution Analysis is refused with a message naming the products it does include.

  • The analysis keeps running when the licence server cannot be reached, for 3 days. A successful check is saved, and inside 24 hours a run does not contact the server at all, as before. When the server cannot be reached, a check saved less than 3 days ago stands in, with a warning each run saying how much of the grace is left. “Cannot be reached” is now anything that is not a verdict on the licence: no connection, a timeout, a redirect, a 400, 408, 422, 425, 429 or 5xx, or a 200 that cannot be read. In 0.2 the grace was 7 days but covered only connection errors and timeouts, and any answer other than a 200, an outage on our side included, rejected the licence outright. The grace runs from the last successful check, never past the expiry the server reported, and ignores a check stamped more than an hour in the future, so neither repeated offline runs nor a rolled-back clock can stretch it.

  • A rejection is final. A 401, 402, 403 or 404, or a 200 whose ok is not true, raises LicenseValidationError at once and deletes the saved check, so going offline cannot bring a revoked licence back. In 0.2 a rejection left the saved check in place, where it went on standing in offline for up to 7 days after the last success, and a 200 whose ok was "yes" or 1 was accepted.

  • Where the saved checks live. One file per licence key, named after the key’s SHA-256 digest, in the folder %LOCALAPPDATA%\KaxaNuk\licence-cache\attribution-analysis on Windows and $XDG_CACHE_HOME/kaxanuk/licence-cache/attribution-analysis elsewhere (~/.cache without XDG_CACHE_HOME); KAXANUK_LICENSE_CACHE_DIR moves them. Each holds the key’s digest, never the key, is signed, is tied to the device and to Attribution Analysis, and is written atomically, so a process that validates several users’ keys, like the Research Lab’s, never mixes them. ~/.kaxanuk_attribution_cache, the single cache of 0.2 and earlier, is neither read nor removed:

  • the first run after upgrading needs to reach the licence server*, and the old file can be deleted by hand.

  • ``.kaxanuk_license`` is read as a ``.env`` file. The line KNAA_API_KEY_KAXANUK=<key> is attribution’s, and a file holding a single key without a name serves every product; in 0.2 the first line counted, whatever product it named. A KNAA_API_KEY_KAXANUK holding only spaces now counts as unset instead of being sent as an empty key.

  • validate_license() returns the client’s ValidationResult: keyword-only, with ok, message and the licence’s expires_at. Code that built attribution’s two-field ValidationResult by position has to name its fields. Every licence message and log line is ASCII and never carries the licence key.

  • Development. kaxanuk-license-client is the only package taken from KaxaNuk’s private index, and it is taken from nowhere else ([[tool.pdm.source]] with include_packages and exclude_packages): installing the project with PDM needs KAXANUK_INDEX_KEY set to a licence key.

  • Read the Docs no longer installs the package. Installing it would need the licence client, which only the private index serves: autodoc imports the package from src/, kaxanuk.license_client is mocked, docs/source/conf.py reads the version from the source instead of importing it, and the docs dependency group now also lists the package’s runtime dependencies.

Fixed#

  • The offline-grace warning reached nobody on a Spanish Windows console. Its em dash cannot be encoded in cp850, and the bare StreamHandler in services.configuration_logger turned that into a UnicodeEncodeError inside logging: the user saw --- Logging error --- and the warning itself was lost. The console is now moved to UTF-8 when it is not on it already, a console that refuses to be reconfigured gets the record with the offending characters replaced rather than no record at all, and the optional log file is written as UTF-8 instead of in the machine’s codepage.

0.2.0 (2026-07-12)#

Added#

  • Input handlers now slices the file right away with the actual start date.

Fixed#

  • Formating in the [attribution_analysis_parameters.xlsx](templates/attribution_analysis/Config/attribution_analysis_parameters.xlsx) configuration

0.1.0 (2026-07-03)#

Added#

  • Brinson-Fachler attribution, decomposing active return into allocation, selection and interaction effects per asset and date.

  • KN Five-Factor Model (KN5FM) attribution, decomposing portfolio return into per-factor contributions plus an idiosyncratic residual.

  • Excel-based configuration workbook (attribution_analysis_parameters.xlsx) and CLI (init, run, update, autorun).

  • CSV and Parquet market data input handlers, and CSV/Excel portfolio and benchmark weight handlers.

  • Interactive Dash dashboard for cumulative factor contributions and summary statistics.

  • License key validation against the KaxaNuk license server, with local caching and an offline grace period.

  • Added a data-integrity check to PortfolioWeights that rejects weight series without

~daily (240–260/year) observation density, catching backtest-granularity files passed in by mistake. * Auto date alignment across all input tables (asset returns, portfolio/benchmark weights,

benchmark returns, factor returns) to their common date range before running any calculation.

  • User-defined column name mapping for market-data inputs, so CSV/Parquet files don’t need to match a fixed schema.

  • Performance statistics module (Sharpe ratio, annualized return/volatility, skewness, kurtosis, max drawdown, historic and Gaussian VaR/CVaR) surfaced in the dashboard’s summary panel.

  • Synthetic factor-exposure generator for prototyping the factor model pipeline without real factor data.

  • PyArrow-based columnar architecture used throughout for high-performance, vectorized computation.

  • Pandas-based reference implementations of both attribution methodologies, provided alongside the PyArrow implementations for validation and comparison.

  • Excel-workbook schema-version check that prompts update excel when the configuration template is outdated.