factormodels 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- factormodels-0.1.0/AGENTS.md +157 -0
- factormodels-0.1.0/CHANGELOG.md +120 -0
- factormodels-0.1.0/CITATION.cff +38 -0
- factormodels-0.1.0/CLAUDE.md +8 -0
- factormodels-0.1.0/CONTRIBUTING.md +141 -0
- factormodels-0.1.0/LICENSE +21 -0
- factormodels-0.1.0/MANIFEST.in +10 -0
- factormodels-0.1.0/PKG-INFO +595 -0
- factormodels-0.1.0/README.md +557 -0
- factormodels-0.1.0/THIRD_PARTY_NOTICES.md +121 -0
- factormodels-0.1.0/docs/api.md +198 -0
- factormodels-0.1.0/docs/cma_diagnostics.md +418 -0
- factormodels-0.1.0/docs/completed_model.md +111 -0
- factormodels-0.1.0/docs/conf.py +9 -0
- factormodels-0.1.0/docs/construction.md +44 -0
- factormodels-0.1.0/docs/factor_covariance_hcgl.md +420 -0
- factormodels-0.1.0/docs/gls_factor_premia.md +431 -0
- factormodels-0.1.0/docs/index.md +40 -0
- factormodels-0.1.0/docs/integration.md +40 -0
- factormodels-0.1.0/docs/licensing.md +55 -0
- factormodels-0.1.0/docs/migration.md +82 -0
- factormodels-0.1.0/docs/reference_workflows.md +88 -0
- factormodels-0.1.0/docs/rolling_factor_covar_from_csv.md +63 -0
- factormodels-0.1.0/examples/construct_factors.py +69 -0
- factormodels-0.1.0/examples/downstream_handoff.py +41 -0
- factormodels-0.1.0/examples/gls_factor_premia.py +171 -0
- factormodels-0.1.0/examples/methods/factor_covariance_hcgl.py +335 -0
- factormodels-0.1.0/examples/methods/gls_factor_premia.py +76 -0
- factormodels-0.1.0/examples/reference_workflows.py +261 -0
- factormodels-0.1.0/pyproject.toml +109 -0
- factormodels-0.1.0/setup.cfg +4 -0
- factormodels-0.1.0/src/factormodels/__init__.py +220 -0
- factormodels-0.1.0/src/factormodels/_estimation.py +1199 -0
- factormodels-0.1.0/src/factormodels/_preparation.py +101 -0
- factormodels-0.1.0/src/factormodels/analytics/__init__.py +20 -0
- factormodels-0.1.0/src/factormodels/analytics/opportunity.py +288 -0
- factormodels-0.1.0/src/factormodels/analytics/tests/__init__.py +1 -0
- factormodels-0.1.0/src/factormodels/analytics/tests/opportunity_guards_test.py +74 -0
- factormodels-0.1.0/src/factormodels/analytics/tests/opportunity_test.py +101 -0
- factormodels-0.1.0/src/factormodels/analytics/tests/prepared_opportunity_test.py +60 -0
- factormodels-0.1.0/src/factormodels/analytics/tests/uncertainty_guards_test.py +124 -0
- factormodels-0.1.0/src/factormodels/analytics/tests/uncertainty_test.py +177 -0
- factormodels-0.1.0/src/factormodels/analytics/tests/universe_diagnostics_guards_test.py +59 -0
- factormodels-0.1.0/src/factormodels/analytics/tests/universe_diagnostics_test.py +163 -0
- factormodels-0.1.0/src/factormodels/analytics/uncertainty.py +243 -0
- factormodels-0.1.0/src/factormodels/analytics/universe_diagnostics.py +205 -0
- factormodels-0.1.0/src/factormodels/bundle.py +465 -0
- factormodels-0.1.0/src/factormodels/cma/__init__.py +26 -0
- factormodels-0.1.0/src/factormodels/cma/diagnostics.py +476 -0
- factormodels-0.1.0/src/factormodels/cma/identification.py +234 -0
- factormodels-0.1.0/src/factormodels/cma/moments.py +75 -0
- factormodels-0.1.0/src/factormodels/cma/tests/__init__.py +1 -0
- factormodels-0.1.0/src/factormodels/cma/tests/cma_diagnostics_test.py +352 -0
- factormodels-0.1.0/src/factormodels/cma/tests/cma_identification_test.py +223 -0
- factormodels-0.1.0/src/factormodels/cma/tests/cma_uncertainty_test.py +123 -0
- factormodels-0.1.0/src/factormodels/cma/tests/moments_test.py +101 -0
- factormodels-0.1.0/src/factormodels/cma/uncertainty.py +70 -0
- factormodels-0.1.0/src/factormodels/constraints.py +103 -0
- factormodels-0.1.0/src/factormodels/construction.py +436 -0
- factormodels-0.1.0/src/factormodels/estimation/tests/estimator_properties_test.py +136 -0
- factormodels-0.1.0/src/factormodels/estimation.py +225 -0
- factormodels-0.1.0/src/factormodels/examples.py +42 -0
- factormodels-0.1.0/src/factormodels/model.py +236 -0
- factormodels-0.1.0/src/factormodels/portfolio_context.py +59 -0
- factormodels-0.1.0/src/factormodels/premia/README.md +240 -0
- factormodels-0.1.0/src/factormodels/premia/__init__.py +67 -0
- factormodels-0.1.0/src/factormodels/premia/_inference.py +364 -0
- factormodels-0.1.0/src/factormodels/premia/_opportunity.py +145 -0
- factormodels-0.1.0/src/factormodels/premia/_resolution.py +121 -0
- factormodels-0.1.0/src/factormodels/premia/_scenarios.py +290 -0
- factormodels-0.1.0/src/factormodels/premia/_stability.py +267 -0
- factormodels-0.1.0/src/factormodels/premia/sharpe_accounting.py +353 -0
- factormodels-0.1.0/src/factormodels/premia/tests/__init__.py +1 -0
- factormodels-0.1.0/src/factormodels/premia/tests/extensions_test.py +416 -0
- factormodels-0.1.0/src/factormodels/premia/tests/gls_rank_test.py +93 -0
- factormodels-0.1.0/src/factormodels/premia/tests/inference_test.py +171 -0
- factormodels-0.1.0/src/factormodels/premia/tests/residual_opportunity_test.py +102 -0
- factormodels-0.1.0/src/factormodels/premia/tests/sharpe_accounting_test.py +290 -0
- factormodels-0.1.0/src/factormodels/reports/__init__.py +1 -0
- factormodels-0.1.0/src/factormodels/reports/cma_diagnostics.py +646 -0
- factormodels-0.1.0/src/factormodels/reports/cma_inference.py +993 -0
- factormodels-0.1.0/src/factormodels/reports/covariance.py +210 -0
- factormodels-0.1.0/src/factormodels/reports/tests/__init__.py +1 -0
- factormodels-0.1.0/src/factormodels/reports/tests/cma_diagnostics_test.py +344 -0
- factormodels-0.1.0/src/factormodels/reports/tests/cma_inference_test.py +459 -0
- factormodels-0.1.0/src/factormodels/risk.py +99 -0
- factormodels-0.1.0/src/factormodels/signals.py +97 -0
- factormodels-0.1.0/src/factormodels/spec.py +636 -0
- factormodels-0.1.0/src/factormodels/tests/_estimation_fixture.py +34 -0
- factormodels-0.1.0/src/factormodels/tests/bundle_test.py +304 -0
- factormodels-0.1.0/src/factormodels/tests/construction_test.py +316 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/__init__.py +1 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_cadence_penalty.py +151 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_cluster_smoothing.py +245 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_covar_reporting.py +287 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_derived_signs.py +147 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_factor_clustering.py +262 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_factor_estimator_guards.py +389 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_native_factor.py +32 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_residual_covariance.py +260 -0
- factormodels-0.1.0/src/factormodels/tests/estimation/test_risk_export.py +105 -0
- factormodels-0.1.0/src/factormodels/tests/examples_test.py +124 -0
- factormodels-0.1.0/src/factormodels/tests/package_identity_test.py +14 -0
- factormodels-0.1.0/src/factormodels/tests/portfolio_context_test.py +75 -0
- factormodels-0.1.0/src/factormodels/tests/signals_test.py +183 -0
- factormodels-0.1.0/src/factormodels.egg-info/PKG-INFO +595 -0
- factormodels-0.1.0/src/factormodels.egg-info/SOURCES.txt +129 -0
- factormodels-0.1.0/src/factormodels.egg-info/dependency_links.txt +1 -0
- factormodels-0.1.0/src/factormodels.egg-info/requires.txt +12 -0
- factormodels-0.1.0/src/factormodels.egg-info/top_level.txt +1 -0
- factormodels-0.1.0/tests/parity/consumer_manifest.json +173 -0
- factormodels-0.1.0/tests/parity/manifest.json +97 -0
- factormodels-0.1.0/tests/parity/test_replay_reference.py +207 -0
- factormodels-0.1.0/tests/synthetic_data.py +16 -0
- factormodels-0.1.0/tests/test_bundle_load.py +2 -0
- factormodels-0.1.0/tests/test_construction_parity.py +40 -0
- factormodels-0.1.0/tests/test_core_api.py +31 -0
- factormodels-0.1.0/tests/test_cutoff.py +81 -0
- factormodels-0.1.0/tests/test_dependency_floor.py +53 -0
- factormodels-0.1.0/tests/test_documented_contracts.py +176 -0
- factormodels-0.1.0/tests/test_estimation_parity.py +96 -0
- factormodels-0.1.0/tests/test_examples.py +146 -0
- factormodels-0.1.0/tests/test_gls_cma.py +49 -0
- factormodels-0.1.0/tests/test_navigation_refs.py +89 -0
- factormodels-0.1.0/tests/test_readme.py +93 -0
- factormodels-0.1.0/tests/test_reports.py +33 -0
- factormodels-0.1.0/tests/test_risk_export.py +112 -0
- factormodels-0.1.0/tools/check_navigation_refs.py +106 -0
- factormodels-0.1.0/tools/navigation_refs.json +5 -0
- factormodels-0.1.0/tools/replay_reference.py +539 -0
- factormodels-0.1.0/uv.lock +2988 -0
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# FactorModels contributor instructions
|
|
2
|
+
|
|
3
|
+
## Scope and package ownership
|
|
4
|
+
|
|
5
|
+
FactorModels (FM) owns factor construction, complete fitted factor models,
|
|
6
|
+
generalized least squares (GLS), capital market assumption (CMA) analytics and
|
|
7
|
+
method-specific reports. It uses QuantInvestStrats (`qis`) and FactorLasso for
|
|
8
|
+
shared analytics and statistical estimation. OptimalPortfolios consumes supplied
|
|
9
|
+
alphas and covariance; application-specific recipes, providers and scheduling
|
|
10
|
+
belong to downstream consumers. The library must not import those consumers.
|
|
11
|
+
|
|
12
|
+
Follow the current task's explicit scope. Historical migration decisions are not
|
|
13
|
+
blanket permission for new public-interface or numerical changes. Keep the
|
|
14
|
+
canonical `factormodels` interface without retired-package forwarding modules or
|
|
15
|
+
an OptimalPortfolios compatibility extra. Numerical changes require explicit
|
|
16
|
+
authorisation and independent reference evidence.
|
|
17
|
+
|
|
18
|
+
## Environment and outputs
|
|
19
|
+
|
|
20
|
+
Use the portable source, lint, test, build and documentation commands in
|
|
21
|
+
[CONTRIBUTING.md](CONTRIBUTING.md). Work from an external checkout for builds and
|
|
22
|
+
keep environments, caches, reports and temporary output outside synchronised
|
|
23
|
+
folders. Select the declared dependency groups and use the reviewed lockfile.
|
|
24
|
+
|
|
25
|
+
On the registered maintainer Windows/OneDrive workspace, use
|
|
26
|
+
`C:\Python\FactorModels312\Scripts\python.exe`. Never create or use a virtual
|
|
27
|
+
environment, cache, build or temporary output tree inside OneDrive. Before manual
|
|
28
|
+
Python or check commands, dot-source the workspace
|
|
29
|
+
`ArturSepp/scripts/repo_governance/Enter-AgentRepo.ps1` for this repository. The
|
|
30
|
+
registered launcher provides `check`, `test`, `verify` and `docs` tasks. Generated
|
|
31
|
+
state belongs under the external `AGENT_LOCAL_ROOT`; project `uv` operations must
|
|
32
|
+
set `UV_PROJECT_ENVIRONMENT` to the external environment explicitly. Preserve any
|
|
33
|
+
frozen historical environment and use a separate environment for candidate work.
|
|
34
|
+
|
|
35
|
+
## Public API and tests
|
|
36
|
+
|
|
37
|
+
Use Google-style docstrings, explicit module exports and root `__all__`. The root
|
|
38
|
+
public export list is the canonical package application programming interface
|
|
39
|
+
(API). Test canonical objects and their contracts. Keep deterministic synthetic
|
|
40
|
+
fixtures free of private data and provider dependencies. Source-adjacent tests
|
|
41
|
+
are shipped for installed-wheel checks; top-level tests hold package acceptance
|
|
42
|
+
contracts. Examples use an explicit `run_local_test(case)` entry point and run
|
|
43
|
+
offline unless they explicitly describe an optional acquisition action.
|
|
44
|
+
|
|
45
|
+
Every fitted result states cutoff, ordering, return transformations, annualisation,
|
|
46
|
+
currency when supplied, selected residual policy and relevant provenance. The
|
|
47
|
+
`qis.RiskModel` is an interchange view, not the complete fitted result. Preserve
|
|
48
|
+
full selected covariance; label diagonal-reference decompositions explicitly.
|
|
49
|
+
|
|
50
|
+
Read the [shared documentation standard](https://github.com/ArturSepp/ArturSepp/blob/main/docs/documentation_standard.md)
|
|
51
|
+
before substantive reader-facing documentation edits. Maintain `LICENSE`,
|
|
52
|
+
supplemental notices, `CITATION.cff`, the README citation and `CHANGELOG.md`.
|
|
53
|
+
Version metadata must agree. Keep generated analyses and private inputs out of
|
|
54
|
+
source distributions and the public repository.
|
|
55
|
+
|
|
56
|
+
## Generated shared instructions
|
|
57
|
+
|
|
58
|
+
The block below is generated from the maintainer's shared instruction source.
|
|
59
|
+
Amend that source and run its scoped producer; do not hand-edit the block or
|
|
60
|
+
change unrelated repository emissions. The current task's authorisation defines
|
|
61
|
+
which files and public-interface changes are in scope.
|
|
62
|
+
|
|
63
|
+
<!-- ===== SHARED AGENT CORE (consumer variant) — begin =====
|
|
64
|
+
Generated from SHARED_AGENT_CORE.md in the maintainer's project knowledge. Do not hand-edit
|
|
65
|
+
between these markers — propose the change to the maintainer instead. Variants: builder
|
|
66
|
+
(qis) / consumer / standalone. Last synced 2026-10-20, agent core v1.6; scoped FactorModels amendment -->
|
|
67
|
+
|
|
68
|
+
## Domain invariants
|
|
69
|
+
|
|
70
|
+
Not inferable from any single file, and the source of numerically wrong code that runs clean:
|
|
71
|
+
|
|
72
|
+
- **No look-ahead, anywhere in a backtest path.** A weight decided at *t* is applied over
|
|
73
|
+
*[t, t+1]*. Estimation is point-in-time: `MeanAdjType.INSAMPLE` subtracts a full-sample mean
|
|
74
|
+
and is therefore forward-looking — correct for a descriptive exhibit, wrong inside a backtest.
|
|
75
|
+
- **Return convention is stated, never implied** — `qis.to_returns(..., is_log_returns=...)`.
|
|
76
|
+
Annualisation follows from the frequency; never silently switch convention, frequency, or
|
|
77
|
+
annualisation factor.
|
|
78
|
+
- **Sharpe has three explicitly labelled conventions** in `qis`; excess variants need
|
|
79
|
+
`PerfParams.rates_data`. State which one a number uses.
|
|
80
|
+
- **`qis.BootstrapType.STATIONARY` wraps circularly from qis 5.1.0.** Any result resampled under
|
|
81
|
+
an earlier version does not reproduce.
|
|
82
|
+
- One convention per concept across the stack. If two packages disagree, that is a bug to
|
|
83
|
+
report, not a difference to accommodate.
|
|
84
|
+
|
|
85
|
+
## Use the stack before you write it
|
|
86
|
+
|
|
87
|
+
This package consumes `qis` (analytics, backtesting, risk, stress testing and reporting) and
|
|
88
|
+
`factorlasso` (statistical estimation and fitted-data containers). FactorModels owns the
|
|
89
|
+
complete factor construction and estimation pipeline that connects them. Its finite outputs
|
|
90
|
+
are factor definitions, net asset value (NAV) histories and fitted loadings/covariance for an asset universe; document
|
|
91
|
+
which construction stages are available and each object's downstream usage. OptimalPortfolios consumes
|
|
92
|
+
explicit alphas and covariance for optimisation. Reimplementing an upstream capability is
|
|
93
|
+
a defect, not a convenience.
|
|
94
|
+
Triggers — stop and check the export list before writing: backtest, rebalance, turnover,
|
|
95
|
+
drawdown, Sharpe, volatility target, bootstrap, resample, unsmooth, covariance, correlation,
|
|
96
|
+
regime, hedge ratio, factsheet, tracking error, realised tracking error, information ratio,
|
|
97
|
+
benchmark beta, marginal contribution, risk contribution.
|
|
98
|
+
|
|
99
|
+
- **The hard stop:** a `for` loop over dates accumulating a position, a weight or a P&L is
|
|
100
|
+
`qis.backtest_model_portfolio`. The hand-rolled version gets drift adjustment wrong — `qis`
|
|
101
|
+
holds *units* between rebalancings, not weights.
|
|
102
|
+
- **Never hand-roll `d' Σ d`, a beta ratio, or a tracking-error (TE) decomposition.** Ex-ante tracking error,
|
|
103
|
+
factor exposures, benchmark beta and marginal TE come from `qis.RiskModel`, built from
|
|
104
|
+
fitted FactorModels output via `factormodels.build_risk_model`; supplied covariance uses
|
|
105
|
+
`qis.RiskModel(covar={date: covariance})`. Realised ex-post TE is
|
|
106
|
+
`qis.compute_ewma_realised_tracking_error` (EWMA series), and whole-sample TE/IR scalars are
|
|
107
|
+
`qis.compute_te_ir_errors`.
|
|
108
|
+
- **Never invent a symbol.** If a function, class, or keyword argument is not in the export
|
|
109
|
+
list, it does not exist. Check in one line —
|
|
110
|
+
`python -c "import qis; print([n for n in dir(qis) if 'unsmooth' in n.lower()])"`;
|
|
111
|
+
`qis.api.CORE_API` is the documented core and `help(qis.<symbol>)` gives the arguments. Say a
|
|
112
|
+
symbol is missing rather than producing code that calls it.
|
|
113
|
+
- **If you genuinely must reimplement**, name the rejected stack symbol and why, in a comment on
|
|
114
|
+
the line above the definition — that turns a silent divergence into a reviewable decision.
|
|
115
|
+
- Never introduce `quantstats`, `pyfolio`, `empyrical`, `ffn`, `bt`, or an ad-hoc statistics
|
|
116
|
+
layer.
|
|
117
|
+
|
|
118
|
+
## Verification loop
|
|
119
|
+
|
|
120
|
+
- Plan → patch → verify. Name the verification command and its result when proposing a patch.
|
|
121
|
+
- A second pass is mandatory where a plausible patch can be numerically wrong and still run
|
|
122
|
+
clean: estimation windows, weight normalisation, annualisation, constraint construction,
|
|
123
|
+
anything resampled. Verify against a reference computed a different way, and say which.
|
|
124
|
+
- Prove a new test fails before trusting that it passes: reintroduce the defect, watch it fail,
|
|
125
|
+
restore.
|
|
126
|
+
|
|
127
|
+
## Escalation and scope
|
|
128
|
+
|
|
129
|
+
- Stop and propose before proceeding when a change would exceed roughly five files, alter a
|
|
130
|
+
public signature, or touch a numerical path.
|
|
131
|
+
- Never change numerical results, random seeds, or computed values unless the change is the
|
|
132
|
+
request.
|
|
133
|
+
- A public-signature change carries a `CHANGELOG.md` entry and a version bump in the same
|
|
134
|
+
change. Removing a keyword argument from a function taking `**kwargs` is a silent break — the
|
|
135
|
+
caller's keyword is swallowed and nothing raises. Treat it as breaking.
|
|
136
|
+
- Do not refactor beyond the requested scope. Propose the wider change; do not perform it.
|
|
137
|
+
|
|
138
|
+
## Concurrent sessions
|
|
139
|
+
|
|
140
|
+
More than one agent or session may work on this checkout at the same time, so a file can change
|
|
141
|
+
between your read of it and your write.
|
|
142
|
+
|
|
143
|
+
- Re-read a file from disk immediately before editing it. Never write a file from an earlier
|
|
144
|
+
read: a whole-file write from a stale copy silently reverts another session's work.
|
|
145
|
+
- Prefer minimal anchored edits over whole-file replacement. If the on-disk content is not what
|
|
146
|
+
you expected, stop and reconcile your change onto the current content rather than overwrite.
|
|
147
|
+
|
|
148
|
+
## Agent-generated artifacts
|
|
149
|
+
|
|
150
|
+
All agent-generated roadmaps, execution plans, audits, reports, handoffs, and other working
|
|
151
|
+
outputs live under the repository-root `agents/` directory, which is local and ignored by Git.
|
|
152
|
+
Never create `ROADMAP_*.md`, `Claude outputs/`, `Codex outputs/`, or similar agent-output
|
|
153
|
+
artifacts at the repository root. Name feature roadmaps `agents/ROADMAP_<feature>.md`. An
|
|
154
|
+
execution request names the file and stage. A stage is complete when its stated verification
|
|
155
|
+
command passes; its out-of-scope list is binding.
|
|
156
|
+
|
|
157
|
+
<!-- ===== SHARED AGENT CORE — end ===== -->
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
FactorModels constructs multi-asset tradable factor models and provides
|
|
4
|
+
generalized least squares (GLS) and capital market assumption (CMA) diagnostics.
|
|
5
|
+
The first public release is 0.1.0; earlier entries record unpublished development.
|
|
6
|
+
|
|
7
|
+
## 0.1.0 — first public release (2026-10-21)
|
|
8
|
+
|
|
9
|
+
- Publish the canonical `factormodels` distribution and public FactorModels source.
|
|
10
|
+
- Provide factor construction, fitted asset loadings and covariance, rolling models,
|
|
11
|
+
GLS/CMA analytics and explicit QIS/OptimalPortfolios handoffs.
|
|
12
|
+
- Retain the verified candidate algorithms, estimator outputs and numerical defaults.
|
|
13
|
+
- Use public OSS consumer verification and PyPI installation instructions.
|
|
14
|
+
|
|
15
|
+
- Require Python 3.11 or later and Pillow 13 or later to exclude the known
|
|
16
|
+
Pillow vulnerabilities whose fixed release no longer supports Python 3.10.
|
|
17
|
+
- Check the new minimum interpreter in CI and enforce both floors in installed
|
|
18
|
+
package metadata. Estimator source, defaults and numerical conventions are unchanged.
|
|
19
|
+
|
|
20
|
+
## 0.1.0rc4 — unpublished FactorModels rename candidate (2026-10-20)
|
|
21
|
+
|
|
22
|
+
- Rename the distribution and import namespace from `tradablefactors` to
|
|
23
|
+
`factormodels`, displayed as FactorModels (FM). No forwarding package is installed.
|
|
24
|
+
- Retain the public class/member names, fitted estimator outputs, construction
|
|
25
|
+
settings, residual policies, numerical conventions and dependency resolutions.
|
|
26
|
+
- Describe factors as supplied price/level histories with explicit return
|
|
27
|
+
transformations. Bundle schema versions and saved-fit input formats are unchanged.
|
|
28
|
+
- Adapt integrations to the new namespace while retaining the existing repository
|
|
29
|
+
URL.
|
|
30
|
+
- Add portable contributor setup, locked source checks, installed-artifact
|
|
31
|
+
verification and strict documentation build instructions.
|
|
32
|
+
|
|
33
|
+
## 0.1.0rc3 — unpublished release candidate (2026-10-19)
|
|
34
|
+
|
|
35
|
+
- Connect the fitted-model quickstart to GLS/CMA through an explicit second-order
|
|
36
|
+
mean bridge, retaining annual log covariance as the declared risk approximation.
|
|
37
|
+
- Export `annual_arithmetic_from_log` for labelled mean and variance inputs.
|
|
38
|
+
Reconcile arithmetic alpha using both asset and factor variance adjustments.
|
|
39
|
+
- Export fitted-model GLS/CMA tables and a PDF when the teaching assumptions and
|
|
40
|
+
positive diagonal residual geometry apply; retain full model tables otherwise.
|
|
41
|
+
- Clarify citation wording, synthetic shrinkage and downstream use. Preserve
|
|
42
|
+
fitted estimator values, seeds, selected covariance policies and dependencies.
|
|
43
|
+
|
|
44
|
+
## 0.1.0rc2 — unpublished release candidate (2026-10-19)
|
|
45
|
+
|
|
46
|
+
This candidate provides factor definitions and net asset value (NAV) construction, fitted asset
|
|
47
|
+
loadings and annual covariance at a stated cutoff, rolling model estimates,
|
|
48
|
+
GLS factor-premium inference, and CMA diagnostics with method-specific reports.
|
|
49
|
+
Completed model objects retain labels, conventions and provenance for downstream
|
|
50
|
+
risk analysis and portfolio optimisation.
|
|
51
|
+
|
|
52
|
+
Changes since `0.1.0rc1`:
|
|
53
|
+
|
|
54
|
+
- Add labelled, copy-returning `FactorModelSnapshot.loadings` and
|
|
55
|
+
`factor_covariance` properties without changing estimation or covariance values.
|
|
56
|
+
- Install and export `synthetic_bundle()` for an offline quickstart that works
|
|
57
|
+
without a source checkout. Preserve its existing seed, inputs and settings.
|
|
58
|
+
- Keep log-return bundle results separate from arithmetic-excess GLS/CMA reports.
|
|
59
|
+
Bundle examples export fitted tables and explain why no arithmetic audit is
|
|
60
|
+
produced. A separate arithmetic example demonstrates premia, diagnostics and
|
|
61
|
+
explicit report export with consistent cash, alpha and covariance conventions.
|
|
62
|
+
- Clarify the package's completed outputs and downstream use in the README,
|
|
63
|
+
and add the multi-asset tradable factor (MATF) working-paper citation and package discovery metadata.
|
|
64
|
+
- Retain estimator outputs, numerical library implementations and dependency
|
|
65
|
+
versions.
|
|
66
|
+
|
|
67
|
+
## 0.1.0rc1 — unpublished release candidate (2026-10-19)
|
|
68
|
+
|
|
69
|
+
- Align package, citation and README version metadata without numerical or API
|
|
70
|
+
changes.
|
|
71
|
+
- Retain the MIT source licence, supplemental notices and verified MIT FactorLasso
|
|
72
|
+
dependency floor. Dependency versions and resolution remain unchanged.
|
|
73
|
+
|
|
74
|
+
## 0.1.0.dev3 — development (2026-10-18)
|
|
75
|
+
|
|
76
|
+
- Require the verified MIT FactorLasso release `>=1.0.4.post1` in base installs
|
|
77
|
+
and the lock, excluding earlier GPL releases without changing estimation or
|
|
78
|
+
covariance behaviour. Keep optimiser installation a separate consumer step.
|
|
79
|
+
- Ship supplemental OpenBLAS/LAPACK notices and document the reviewed Windows
|
|
80
|
+
compiler-runtime exceptions and vendor redistributables separately from MIT source.
|
|
81
|
+
- Document direct TradableFactors replacements for former OptimalPortfolios
|
|
82
|
+
estimator calls, FactorLasso aliases and result-context helpers; compatibility
|
|
83
|
+
forwarding APIs are not provided.
|
|
84
|
+
- Add the installed, versioned six-file bundle API with explicit loading,
|
|
85
|
+
in-memory fitting and new-directory persistence. Unsupported or unversioned
|
|
86
|
+
settings are rejected; historical bundles remain in their recorded environments.
|
|
87
|
+
- Provide offline synthetic, supplied-bundle and public-proxy reference workflows
|
|
88
|
+
with inspectable results and separate downstream QuantInvestStrats (`qis`) and
|
|
89
|
+
OptimalPortfolios use.
|
|
90
|
+
- Document completed model fields, units, cutoffs and mutability; move factor
|
|
91
|
+
estimation and GLS/CMA method documentation to its owning package.
|
|
92
|
+
|
|
93
|
+
## 0.1.0.dev2 — development (2026-10-18)
|
|
94
|
+
|
|
95
|
+
- Add opportunity GLS diagnostics, alpha-uncertainty inference and universe
|
|
96
|
+
diagnostics formerly in OptimalPortfolios. Return prepared arrays for downstream
|
|
97
|
+
solving.
|
|
98
|
+
- Add `prepare_portfolio_context` for QIS risk and optional diagnostic-table
|
|
99
|
+
handoff, preserving full residual covariance and native factor coordinates.
|
|
100
|
+
- Add rolling cluster extraction and stability-pooled score preparation for
|
|
101
|
+
downstream consumers.
|
|
102
|
+
- Use FactorLasso for statistical estimation and QIS for general risk/reporting
|
|
103
|
+
interfaces, without introducing an optimiser dependency.
|
|
104
|
+
|
|
105
|
+
## 0.1.0.dev1 — development
|
|
106
|
+
|
|
107
|
+
- Add factor families, basket/model specifications and assembly from an explicitly supplied catalogue.
|
|
108
|
+
- Add basket construction, volatility targeting, composite NAVs, supported
|
|
109
|
+
prehistory splicing and loading-sign constraints with explicit numerical policies.
|
|
110
|
+
- Accept caller-supplied label aliases and catalogues without a data-provider
|
|
111
|
+
dependency.
|
|
112
|
+
- Add offline construction examples and independent held-unit, warm-up,
|
|
113
|
+
shared-gate and splice verification.
|
|
114
|
+
|
|
115
|
+
## 0.1.0.dev0 — development
|
|
116
|
+
|
|
117
|
+
- Extract GLS, Sharpe accounting, CMA identification and conditional inference from OptimalPortfolios.
|
|
118
|
+
- Introduce explicit current/rolling fitted results and cutoff-aware factor covariance estimation.
|
|
119
|
+
- Export the selected total covariance to existing QIS risk interfaces with stated decomposition limits.
|
|
120
|
+
- Preserve first-party MIT attribution.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "Please cite the working paper for the MATF methodology and this software metadata for the implementation."
|
|
3
|
+
type: software
|
|
4
|
+
repository-code: "https://github.com/ArturSepp/FactorModels"
|
|
5
|
+
url: "https://github.com/ArturSepp/FactorModels"
|
|
6
|
+
title: "FactorModels: Financial factor models and GLS analytics"
|
|
7
|
+
authors:
|
|
8
|
+
- family-names: Sepp
|
|
9
|
+
given-names: Artur
|
|
10
|
+
orcid: "https://orcid.org/0000-0002-7038-1748"
|
|
11
|
+
license: MIT
|
|
12
|
+
version: 0.1.0
|
|
13
|
+
date-released: "2026-10-21"
|
|
14
|
+
keywords:
|
|
15
|
+
- MATF
|
|
16
|
+
- multi-asset
|
|
17
|
+
- tradable-factors
|
|
18
|
+
- factor-models
|
|
19
|
+
- generalized-least-squares
|
|
20
|
+
- covariance-estimation
|
|
21
|
+
- capital-market-assumptions
|
|
22
|
+
preferred-citation:
|
|
23
|
+
type: report
|
|
24
|
+
title: "Capital Market Assumptions and Strategic Asset Allocation Using Multi-Asset Tradable Factors"
|
|
25
|
+
authors:
|
|
26
|
+
- family-names: Sepp
|
|
27
|
+
given-names: Artur
|
|
28
|
+
orcid: "https://orcid.org/0000-0002-7038-1748"
|
|
29
|
+
- family-names: Hansen
|
|
30
|
+
given-names: Emilie H.
|
|
31
|
+
- family-names: Kastenholz
|
|
32
|
+
given-names: Mika
|
|
33
|
+
year: 2026
|
|
34
|
+
publisher:
|
|
35
|
+
name: SSRN
|
|
36
|
+
doi: "10.2139/ssrn.6785958"
|
|
37
|
+
url: "https://papers.ssrn.com/sol3/papers.cfm?abstract_id=6785958"
|
|
38
|
+
notes: "Working paper. Date written: 2026-05-17."
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# FactorModels agent entry point
|
|
2
|
+
|
|
3
|
+
Read [AGENTS.md](AGENTS.md) for package ownership, numerical invariants and the
|
|
4
|
+
generated shared instructions. Use [CONTRIBUTING.md](CONTRIBUTING.md) for portable
|
|
5
|
+
source, installed-artifact and documentation checks. Its registered maintainer
|
|
6
|
+
section applies only to that workspace; Windows/OneDrive environments and output
|
|
7
|
+
must remain external. Follow the current task's scope and preserve concurrent
|
|
8
|
+
work. Do not infer permission to publish from a successful local check.
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
*Author: [Artur Sepp](https://github.com/ArturSepp) / First recorded: [2026-10-18](https://github.com/ArturSepp/tradablefactors/commit/2e23f5a9334fe2c44a5acfa028e0ac3e368f93a0)*
|
|
4
|
+
|
|
5
|
+
Contribute to [FactorModels](https://github.com/ArturSepp/FactorModels) using a
|
|
6
|
+
reviewed source checkout and the dependency versions in `uv.lock`. See
|
|
7
|
+
[AGENTS.md](AGENTS.md) for numerical and package boundaries and
|
|
8
|
+
[CITATION.cff](CITATION.cff) for software attribution.
|
|
9
|
+
|
|
10
|
+
## Prepare an external checkout
|
|
11
|
+
|
|
12
|
+
Use Python 3.12 and `uv` for the reference contributor commands below. The package
|
|
13
|
+
supports Python 3.11 and later; continuous integration (CI) checks its declared
|
|
14
|
+
platform/interpreter matrix separately. Obtain an authorised checkout of the
|
|
15
|
+
revision you intend to test, and run these commands from its root. A source
|
|
16
|
+
archive also works for the direct checks below; Git-based shared checkers require
|
|
17
|
+
a checkout.
|
|
18
|
+
|
|
19
|
+
Keep this working checkout outside OneDrive or other synchronised folders.
|
|
20
|
+
Builders can write metadata beside source files, so redirecting only the final
|
|
21
|
+
artifact directory is insufficient. Choose one setup block for your shell; it
|
|
22
|
+
places environments, caches and generated results outside the checkout.
|
|
23
|
+
|
|
24
|
+
On Linux or macOS:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
export FM_SOURCE="$PWD"
|
|
28
|
+
export FM_WORK="$(mktemp -d)"
|
|
29
|
+
export UV_PROJECT_ENVIRONMENT="$FM_WORK/venv"
|
|
30
|
+
export UV_CACHE_DIR="$FM_WORK/cache/uv"
|
|
31
|
+
export PYTHONPYCACHEPREFIX="$FM_WORK/cache/python"
|
|
32
|
+
export NUMBA_CACHE_DIR="$FM_WORK/cache/numba"
|
|
33
|
+
export MPLCONFIGDIR="$FM_WORK/cache/matplotlib"
|
|
34
|
+
export MPLBACKEND=Agg
|
|
35
|
+
export PYTEST_ADDOPTS="-o cache_dir='$FM_WORK/cache/pytest' --basetemp='$FM_WORK/tests'"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
On Windows, use PowerShell and an external environment under `C:\Python`:
|
|
39
|
+
|
|
40
|
+
```powershell
|
|
41
|
+
$env:FM_SOURCE = (Get-Location).Path
|
|
42
|
+
$env:FM_WORK = Join-Path $env:LOCALAPPDATA ('FactorModels\contributor-' + [guid]::NewGuid().ToString('N'))
|
|
43
|
+
$env:UV_PROJECT_ENVIRONMENT = 'C:\Python\FactorModelsContributor312'
|
|
44
|
+
$env:UV_CACHE_DIR = Join-Path $env:FM_WORK 'cache\uv'
|
|
45
|
+
$env:PYTHONPYCACHEPREFIX = Join-Path $env:FM_WORK 'cache\python'
|
|
46
|
+
$env:NUMBA_CACHE_DIR = Join-Path $env:FM_WORK 'cache\numba'
|
|
47
|
+
$env:MPLCONFIGDIR = Join-Path $env:FM_WORK 'cache\matplotlib'
|
|
48
|
+
$env:MPLBACKEND = 'Agg'
|
|
49
|
+
$env:PYTEST_ADDOPTS = "-o cache_dir='$($env:FM_WORK)/cache/pytest' --basetemp='$($env:FM_WORK)/tests'"
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Use a different `C:\Python` environment name if that contributor environment is
|
|
53
|
+
already in use. Do not sync an unrelated or frozen historical environment.
|
|
54
|
+
|
|
55
|
+
## Source checks and documentation
|
|
56
|
+
|
|
57
|
+
After the setup block, these commands work in either shell:
|
|
58
|
+
|
|
59
|
+
```console
|
|
60
|
+
uv sync --locked --python 3.12 --group test --group lint --extra docs
|
|
61
|
+
uv run --no-sync ruff check src tests tools
|
|
62
|
+
uv run --no-sync interrogate
|
|
63
|
+
uv run --no-sync deptry src
|
|
64
|
+
uv run --no-sync pytest
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The `test` and `lint` dependency groups supply the reviewed tools; the `docs`
|
|
68
|
+
extra supplies Sphinx and its extensions. `--locked` rejects a stale lockfile
|
|
69
|
+
instead of changing the dependency cohort. Keep intentional dependency updates
|
|
70
|
+
separate from unrelated source changes.
|
|
71
|
+
|
|
72
|
+
Build the source distribution and then its wheel with the default `build`
|
|
73
|
+
sequence, and build HTML with warnings treated as errors. On Linux or macOS:
|
|
74
|
+
|
|
75
|
+
```sh
|
|
76
|
+
uv run --no-sync python -m build --outdir "$FM_WORK/dist"
|
|
77
|
+
uv run --no-sync python -m sphinx -E -W --keep-going -b html docs "$FM_WORK/html"
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
The equivalent PowerShell commands are:
|
|
81
|
+
|
|
82
|
+
```powershell
|
|
83
|
+
uv run --no-sync python -m build --outdir "$env:FM_WORK\dist"
|
|
84
|
+
uv run --no-sync python -m sphinx -E -W --keep-going -b html docs "$env:FM_WORK\html"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Installed-artifact checks
|
|
88
|
+
|
|
89
|
+
An editable source install does not verify wheel contents. Install the newly
|
|
90
|
+
built wheel into a separate environment and run from an empty directory, using
|
|
91
|
+
its absolute Python path. For a reproducible acceptance run, export the locked
|
|
92
|
+
runtime and test requirements with `uv export --locked --group test --no-dev
|
|
93
|
+
--no-emit-project`, install that export, then install the wheel with `--no-deps`.
|
|
94
|
+
Do not use `uv run` from the source project for the installed check: it selects
|
|
95
|
+
the project's editable environment.
|
|
96
|
+
|
|
97
|
+
Run `python -m pytest --pyargs factormodels` with that installed interpreter.
|
|
98
|
+
Also pass the absolute source paths for `tests/test_bundle_load.py`,
|
|
99
|
+
`tests/test_examples.py`, `tests/test_readme.py`, `tests/test_documented_contracts.py` and
|
|
100
|
+
`tests/test_dependency_floor.py`. Those top-level acceptance contracts complement
|
|
101
|
+
the shipped source-adjacent tests; their collection counts need not match.
|
|
102
|
+
Confirm `factormodels.__file__` resolves inside the installed environment.
|
|
103
|
+
The wheel job in [.github/workflows/ci.yml](.github/workflows/ci.yml) records the
|
|
104
|
+
installed execution contract.
|
|
105
|
+
|
|
106
|
+
## Numerical and contribution rules
|
|
107
|
+
|
|
108
|
+
Keep tests deterministic and offline. Every numerical change needs an independent
|
|
109
|
+
reference calculation, and a new regression check must detect its controlled
|
|
110
|
+
counterexample. Preserve input units, cutoffs, dates, labels, seeds, return
|
|
111
|
+
transformations, annualisation and the selected residual policy. Compare changed
|
|
112
|
+
interfaces through their numerical outputs. The library must not import its
|
|
113
|
+
optimisation or application consumers.
|
|
114
|
+
|
|
115
|
+
Offline examples require neither acquisition services nor an optimiser package.
|
|
116
|
+
Public data acquisition and the OptimalPortfolios composed example are explicit,
|
|
117
|
+
separate actions. Use the runnable sources linked from the
|
|
118
|
+
[reference workflows](docs/reference_workflows.md).
|
|
119
|
+
|
|
120
|
+
Contribute source, tests and documentation. Keep local `agents/` records,
|
|
121
|
+
production bundles, market-data snapshots, generated reports and manuscripts out
|
|
122
|
+
of Git and distributions. Preserve the source licence and supplemental notices;
|
|
123
|
+
see the [licensing guide](docs/licensing.md).
|
|
124
|
+
|
|
125
|
+
## Registered maintainer workspace
|
|
126
|
+
|
|
127
|
+
On the maintainer's Windows/OneDrive checkout, use
|
|
128
|
+
`C:\Python\FactorModels312\Scripts\python.exe` and the registered
|
|
129
|
+
`ArturSepp/scripts/repo_governance/Enter-AgentRepo.ps1` helper before manual Python
|
|
130
|
+
or check commands. The helper sets the external `AGENT_LOCAL_ROOT` and routes
|
|
131
|
+
caches and temporary state to local storage. Never create or use a virtual
|
|
132
|
+
environment inside OneDrive, and never run a project `uv` command there without
|
|
133
|
+
an explicit external `UV_PROJECT_ENVIRONMENT`.
|
|
134
|
+
|
|
135
|
+
Use the registered `Invoke-Repo.ps1 -Repo FactorModels -Task verify` or `-Task docs`
|
|
136
|
+
launcher when that maintainer workspace is available. The shared documentation
|
|
137
|
+
checker validates the staged selection by default; for unstaged work use
|
|
138
|
+
`.github/oss_checks.py docs --working-tree --python <external-python>` with an
|
|
139
|
+
external `--output-dir`, after the helper. Builds use the existing external
|
|
140
|
+
source-export path. These registered helpers are local conveniences, not
|
|
141
|
+
prerequisites for the direct contributor commands above.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Artur Sepp
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
include AGENTS.md CLAUDE.md CONTRIBUTING.md CITATION.cff CHANGELOG.md uv.lock
|
|
2
|
+
recursive-include docs *.md *.py
|
|
3
|
+
recursive-include examples *.py
|
|
4
|
+
recursive-include tests *.py *.json
|
|
5
|
+
recursive-include tools *.py
|
|
6
|
+
include tools/navigation_refs.json
|
|
7
|
+
recursive-include src *.md
|
|
8
|
+
prune agents
|
|
9
|
+
global-exclude *.pyc
|
|
10
|
+
global-exclude *.pyo
|