Skip to main content

Factor attribution and marketplace analytics CLI

Project description

FactorLens

FactorLens is an offline-first factor attribution assistant in Rust.

It computes statistical factors (PCA) from price history, writes artifacts, and supports explainability through a pluggable LLM backend interface (local and bedrock).

MVP Features

  • Price ingestion from CSV
  • PCA factor model fitting
  • Portfolio factor attribution
  • Residual outlier detection
  • Artifact outputs (json + csv)
  • Markdown report generation
  • Explain command using a local llama.cpp backend (llama-cli) with a Bedrock-ready backend contract

Workspace Layout

  • crates/factor_core: Returns, PCA, attribution math
  • crates/factor_io: CSV IO and artifact writing
  • crates/factor_cli: CLI binary (factorlens)
  • crates/llm_local: LLMClient trait + local/bedrock backends
  • crates/report: Markdown report generation

Build Instructions

Build Rust CLI (local)

cargo build -p factor_cli

Release binary:

cargo build -p factor_cli --release

Build Python wheel (local)

python -m pip install --upgrade maturin
maturin build --release --manifest-path crates/factor_cli/Cargo.toml

Install built wheel:

python -m pip install target/wheels/factorlens-*.whl

Build + publish wheels via GitHub Actions (recommended for cross-platform)

# tag-based release build/publish
git tag v0.1.3
git push origin v0.1.3

# or manual workflow trigger
gh workflow run release.yml -f publish_to_pypi=true -f ref=main

Input Formats

prices.csv

  • date (YYYY-MM-DD)
  • ticker
  • close

portfolio.csv (optional)

  • ticker
  • weight

holdings.csv (optional alternative to portfolio.csv)

  • ticker
  • either market_value or both shares and price

factors.csv (for known-factor regression mode)

  • date (YYYY-MM-DD)
  • one or more numeric factor columns (for example: MKT, SMB, HML)

Quick Start

cargo run -p factor_cli -- factors fit \
  --prices data/prices.csv \
  --k 3 \
  --out artifacts/ \
  --portfolio data/portfolio.csv

# safer residual analysis: auto-pick k (< number of assets)
cargo run -p factor_cli -- factors fit \
  --prices data/prices.csv \
  --k-auto \
  --out artifacts/ \
  --portfolio data/portfolio.csv

# alternative: derive weights automatically from holdings
cargo run -p factor_cli -- factors fit \
  --prices data/prices.csv \
  --k 3 \
  --out artifacts/ \
  --holdings data/holdings.csv

cargo run -p factor_cli -- report \
  --artifacts artifacts/ \
  --format markdown \
  --out artifacts/report.md

# known-factor regression mode (MKT/SMB/HML-style)
cargo run -p factor_cli -- factors regress \
  --prices data/prices.csv \
  --factors data/factors.csv \
  --out artifacts/ \
  --portfolio data/portfolio.csv

cargo run -p factor_cli -- explain \
  --backend local \
  --model models/llama.gguf \
  --artifacts artifacts/ \
  --question "What drove the largest drawdown?"

Notes

  • explain --backend local expects llama-cli on your PATH.
  • explain --backend bedrock uses AWS Bedrock via AWS CLI (aws bedrock-runtime converse).
  • This project is designed for explainability of computed analytics, not market prediction.

Python (pip) Package

FactorLens is published as a platform-specific binary wheel via maturin.

Build/install locally:

python -m pip install --upgrade maturin
maturin build --release --manifest-path crates/factor_cli/Cargo.toml
python -m pip install target/wheels/factorlens-*.whl

Run:

factorlens factors fit --prices data/prices.csv --k 3 --out artifacts/

Explainability Notes

  • factors fit excludes weekend dates by default.
  • Pass --include-weekends if your dataset intentionally includes weekend trading.
  • explain supports focused analysis with --focus-factors.

Examples:

cargo run -p factor_cli -- factors fit --prices data/prices.csv --k 3 --out artifacts/ --portfolio data/portfolio.csv
cargo run -p factor_cli -- factors fit --prices data/prices.csv --k 3 --out artifacts/ --portfolio data/portfolio.csv --include-weekends

cargo run -p factor_cli -- explain --backend local --model models/llama_instruct.gguf --artifacts artifacts/ --question "What drove the largest drawdown?" --focus-factors factor_1,factor_2

Custom Factor Names

By default, FactorLens auto-generates factor names from your dataset loadings (top positive and negative loading tickers per factor), so it works on any dataset.

You can still override labels with a CSV or TSV file via --factor-labels.

Example data/factor_labels.csv:

factor,label
factor_1_contrib,Broad Market Beta
factor_2_contrib,Growth vs Value Rotation
factor_3_contrib,Idiosyncratic Spread

Use in explain:

cargo run -p factor_cli -- explain --backend local --model models/llama_instruct.gguf --artifacts artifacts/ --question "What drove the largest drawdown?" --factor-labels data/factor_labels.csv

Notes:

  • Factor keys may be factor_1, factor_1_contrib, or just 1.
  • # comment lines are ignored.

Suggested Questions

  • What was the worst modeled drawdown day, and what factors drove it?
  • On the worst day, what percentage came from each factor?
  • Which factor is my largest average downside contributor over the full sample?
  • Which dates had the biggest positive factor-driven gains?
  • Which 5 days had the largest residuals (moves not explained by factors)?
  • Did my risk concentration increase in the last month?
  • Is my portfolio dominated by one factor or diversified across factors?
  • How stable are exposures across time windows?
  • Which factor changed direction most often?
  • Which factor contributed most to volatility, not just returns?
  • If I remove factor_1, how much modeled downside is left?
  • Compare drawdown drivers with and without weekends included.
  • Using only factor_1,factor_2, what drove the drawdown?
  • Which assets are most aligned with factor_1 loadings?
  • Which assets increased my exposure to downside factors most?

Marketplace Analysis

Analyze generic marketplace CSVs by group columns you choose:

cargo run -p factor_cli -- marketplace analyze \
  --input data/gold_marketplace_report5000.csv \
  --group-by discipline,category,subcategory,ware_name,advantage_plan \
  --out artifacts/market_report.md

# filtered + ranked view
cargo run -p factor_cli -- marketplace analyze \
  --input data/gold_marketplace_report5000.csv \
  --where advantage_plan=1 \
  --rank-by net_gmv \
  --top 10 \
  --out artifacts/market_filtered_ranked.md

Auto-detect useful grouping columns (if --group-by is omitted):

cargo run -p factor_cli -- marketplace analyze \
  --input data/gold_marketplace_report5000.csv \
  --out artifacts/market_auto.md

Notes:

  • ware_name alias maps to quote_group_ware_name.
  • Outputs both markdown and JSON (<out>.json).
  • Default metrics: net_gmv, customer_purchase_order_retail_total_price_usd, provider_purchase_order_wholesale_total_price_usd.
  • --where accepts comma-separated column=value filters (AND semantics).
  • --rank-by ranks groups by a chosen metric (default ranking is by count).
  • --top controls how many groups are listed in the report.
  • For cleaner executive analytics on this dataset, start with --group-by discipline,advantage_plan.

PyPI Publishing (Rustream-Style)

FactorLens uses the same publishing pattern as rustream: maturin + GitHub Actions to build platform wheels (Linux/macOS/Windows) and publish to PyPI.

Release from macOS via CLI

  1. Bump version in pyproject.toml.
  2. Commit and push to main.
  3. Create and push a release tag:
git tag v0.1.3
git push origin v0.1.3

This triggers .github/workflows/release.yml, which:

  • builds platform-specific wheels via maturin
  • publishes to PyPI using PYPI_API_TOKEN
  • attaches wheels to GitHub Release

To manually trigger from CLI without a tag:

gh workflow run release.yml -f publish_to_pypi=true -f ref=main
gh run list --workflow release.yml
gh run view <run-id> --log

Jupyter Usage

Install from PyPI in Jupyter:

pip install --upgrade factorlens==0.1.3
factorlens --help

Local model:

factorlens explain \
  --backend local \
  --model /path/to/model.gguf \
  --artifacts /path/to/artifacts \
  --question "What drove the largest drawdown?"

Bedrock:

export AWS_REGION=us-east-1
factorlens explain \
  --backend bedrock \
  --model anthropic.claude-3-5-sonnet-20240620-v1:0 \
  --artifacts /path/to/artifacts \
  --question "What drove the largest drawdown?"

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

factorlens-0.1.3-py3-none-win_amd64.whl (752.6 kB view details)

Uploaded Python 3Windows x86-64

factorlens-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (848.7 kB view details)

Uploaded Python 3manylinux: glibc 2.17+ x86-64

factorlens-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (778.2 kB view details)

Uploaded Python 3manylinux: glibc 2.17+ ARM64

factorlens-0.1.3-py3-none-macosx_11_0_arm64.whl (755.5 kB view details)

Uploaded Python 3macOS 11.0+ ARM64

factorlens-0.1.3-py3-none-macosx_10_12_x86_64.whl (809.5 kB view details)

Uploaded Python 3macOS 10.12+ x86-64

File details

Details for the file factorlens-0.1.3-py3-none-win_amd64.whl.

File metadata

  • Download URL: factorlens-0.1.3-py3-none-win_amd64.whl
  • Upload date:
  • Size: 752.6 kB
  • Tags: Python 3, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for factorlens-0.1.3-py3-none-win_amd64.whl
Algorithm Hash digest
SHA256 39671302a8d6aaed4f5301f7e713e7b98f37b06ee78ffb98eb93ff2ccff5f066
MD5 7bac046fdbfa5e0038683c3667a489db
BLAKE2b-256 e323e2b8d0c41a2a6d7bb4ce29d5f4f5d880bf52a86f08398fb53a425fb7d3bc

See more details on using hashes here.

Provenance

The following attestation bundles were made for factorlens-0.1.3-py3-none-win_amd64.whl:

Publisher: release.yml on kraftaa/factorlens

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file factorlens-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for factorlens-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 6b0a56a2f3f8470d15aebf84da58656f8b928cbdff08550c27883a4f48e340b9
MD5 a89f8105ac0e335bfbd58ac421ce675b
BLAKE2b-256 d679e15d2b3a588dca4566cc290f6c38b62c1c44b7ce0a848b16a134f45f86be

See more details on using hashes here.

Provenance

The following attestation bundles were made for factorlens-0.1.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on kraftaa/factorlens

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file factorlens-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for factorlens-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 251a6d6bcd0fd85f14bbf19540c5422f85e2611cef46a8d6c56a8e39cdcb4b06
MD5 274b9b03f2d0328deec028f622d16399
BLAKE2b-256 17946460eb61293d555cda5ab84b64c580cd2331f9d7a858ac374303df403412

See more details on using hashes here.

Provenance

The following attestation bundles were made for factorlens-0.1.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on kraftaa/factorlens

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file factorlens-0.1.3-py3-none-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for factorlens-0.1.3-py3-none-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 472d41d36c6c223bc1d995261ccd669b84bf817407dd7ffb71bcf4ccbbf8a6cd
MD5 b93407cc7267f96a514bebe1ea09b859
BLAKE2b-256 f5ca9df9752630763f188f5f9d7d8cfb093f82279d215323ca2a6b4c0db07800

See more details on using hashes here.

Provenance

The following attestation bundles were made for factorlens-0.1.3-py3-none-macosx_11_0_arm64.whl:

Publisher: release.yml on kraftaa/factorlens

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file factorlens-0.1.3-py3-none-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for factorlens-0.1.3-py3-none-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 e6f537ca69413e66d70dde990b84efc11a79ff2b696498deaf5b3707e97a2ad0
MD5 eb099edf22d15d4ed4ee985bab68330d
BLAKE2b-256 45820881e5d34599f5e2bf1f2b3c3c5a16f1c9ed35e108a3b68e8ff5ad71e761

See more details on using hashes here.

Provenance

The following attestation bundles were made for factorlens-0.1.3-py3-none-macosx_10_12_x86_64.whl:

Publisher: release.yml on kraftaa/factorlens

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page