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.
Files changed (131) hide show
  1. factormodels-0.1.0/AGENTS.md +157 -0
  2. factormodels-0.1.0/CHANGELOG.md +120 -0
  3. factormodels-0.1.0/CITATION.cff +38 -0
  4. factormodels-0.1.0/CLAUDE.md +8 -0
  5. factormodels-0.1.0/CONTRIBUTING.md +141 -0
  6. factormodels-0.1.0/LICENSE +21 -0
  7. factormodels-0.1.0/MANIFEST.in +10 -0
  8. factormodels-0.1.0/PKG-INFO +595 -0
  9. factormodels-0.1.0/README.md +557 -0
  10. factormodels-0.1.0/THIRD_PARTY_NOTICES.md +121 -0
  11. factormodels-0.1.0/docs/api.md +198 -0
  12. factormodels-0.1.0/docs/cma_diagnostics.md +418 -0
  13. factormodels-0.1.0/docs/completed_model.md +111 -0
  14. factormodels-0.1.0/docs/conf.py +9 -0
  15. factormodels-0.1.0/docs/construction.md +44 -0
  16. factormodels-0.1.0/docs/factor_covariance_hcgl.md +420 -0
  17. factormodels-0.1.0/docs/gls_factor_premia.md +431 -0
  18. factormodels-0.1.0/docs/index.md +40 -0
  19. factormodels-0.1.0/docs/integration.md +40 -0
  20. factormodels-0.1.0/docs/licensing.md +55 -0
  21. factormodels-0.1.0/docs/migration.md +82 -0
  22. factormodels-0.1.0/docs/reference_workflows.md +88 -0
  23. factormodels-0.1.0/docs/rolling_factor_covar_from_csv.md +63 -0
  24. factormodels-0.1.0/examples/construct_factors.py +69 -0
  25. factormodels-0.1.0/examples/downstream_handoff.py +41 -0
  26. factormodels-0.1.0/examples/gls_factor_premia.py +171 -0
  27. factormodels-0.1.0/examples/methods/factor_covariance_hcgl.py +335 -0
  28. factormodels-0.1.0/examples/methods/gls_factor_premia.py +76 -0
  29. factormodels-0.1.0/examples/reference_workflows.py +261 -0
  30. factormodels-0.1.0/pyproject.toml +109 -0
  31. factormodels-0.1.0/setup.cfg +4 -0
  32. factormodels-0.1.0/src/factormodels/__init__.py +220 -0
  33. factormodels-0.1.0/src/factormodels/_estimation.py +1199 -0
  34. factormodels-0.1.0/src/factormodels/_preparation.py +101 -0
  35. factormodels-0.1.0/src/factormodels/analytics/__init__.py +20 -0
  36. factormodels-0.1.0/src/factormodels/analytics/opportunity.py +288 -0
  37. factormodels-0.1.0/src/factormodels/analytics/tests/__init__.py +1 -0
  38. factormodels-0.1.0/src/factormodels/analytics/tests/opportunity_guards_test.py +74 -0
  39. factormodels-0.1.0/src/factormodels/analytics/tests/opportunity_test.py +101 -0
  40. factormodels-0.1.0/src/factormodels/analytics/tests/prepared_opportunity_test.py +60 -0
  41. factormodels-0.1.0/src/factormodels/analytics/tests/uncertainty_guards_test.py +124 -0
  42. factormodels-0.1.0/src/factormodels/analytics/tests/uncertainty_test.py +177 -0
  43. factormodels-0.1.0/src/factormodels/analytics/tests/universe_diagnostics_guards_test.py +59 -0
  44. factormodels-0.1.0/src/factormodels/analytics/tests/universe_diagnostics_test.py +163 -0
  45. factormodels-0.1.0/src/factormodels/analytics/uncertainty.py +243 -0
  46. factormodels-0.1.0/src/factormodels/analytics/universe_diagnostics.py +205 -0
  47. factormodels-0.1.0/src/factormodels/bundle.py +465 -0
  48. factormodels-0.1.0/src/factormodels/cma/__init__.py +26 -0
  49. factormodels-0.1.0/src/factormodels/cma/diagnostics.py +476 -0
  50. factormodels-0.1.0/src/factormodels/cma/identification.py +234 -0
  51. factormodels-0.1.0/src/factormodels/cma/moments.py +75 -0
  52. factormodels-0.1.0/src/factormodels/cma/tests/__init__.py +1 -0
  53. factormodels-0.1.0/src/factormodels/cma/tests/cma_diagnostics_test.py +352 -0
  54. factormodels-0.1.0/src/factormodels/cma/tests/cma_identification_test.py +223 -0
  55. factormodels-0.1.0/src/factormodels/cma/tests/cma_uncertainty_test.py +123 -0
  56. factormodels-0.1.0/src/factormodels/cma/tests/moments_test.py +101 -0
  57. factormodels-0.1.0/src/factormodels/cma/uncertainty.py +70 -0
  58. factormodels-0.1.0/src/factormodels/constraints.py +103 -0
  59. factormodels-0.1.0/src/factormodels/construction.py +436 -0
  60. factormodels-0.1.0/src/factormodels/estimation/tests/estimator_properties_test.py +136 -0
  61. factormodels-0.1.0/src/factormodels/estimation.py +225 -0
  62. factormodels-0.1.0/src/factormodels/examples.py +42 -0
  63. factormodels-0.1.0/src/factormodels/model.py +236 -0
  64. factormodels-0.1.0/src/factormodels/portfolio_context.py +59 -0
  65. factormodels-0.1.0/src/factormodels/premia/README.md +240 -0
  66. factormodels-0.1.0/src/factormodels/premia/__init__.py +67 -0
  67. factormodels-0.1.0/src/factormodels/premia/_inference.py +364 -0
  68. factormodels-0.1.0/src/factormodels/premia/_opportunity.py +145 -0
  69. factormodels-0.1.0/src/factormodels/premia/_resolution.py +121 -0
  70. factormodels-0.1.0/src/factormodels/premia/_scenarios.py +290 -0
  71. factormodels-0.1.0/src/factormodels/premia/_stability.py +267 -0
  72. factormodels-0.1.0/src/factormodels/premia/sharpe_accounting.py +353 -0
  73. factormodels-0.1.0/src/factormodels/premia/tests/__init__.py +1 -0
  74. factormodels-0.1.0/src/factormodels/premia/tests/extensions_test.py +416 -0
  75. factormodels-0.1.0/src/factormodels/premia/tests/gls_rank_test.py +93 -0
  76. factormodels-0.1.0/src/factormodels/premia/tests/inference_test.py +171 -0
  77. factormodels-0.1.0/src/factormodels/premia/tests/residual_opportunity_test.py +102 -0
  78. factormodels-0.1.0/src/factormodels/premia/tests/sharpe_accounting_test.py +290 -0
  79. factormodels-0.1.0/src/factormodels/reports/__init__.py +1 -0
  80. factormodels-0.1.0/src/factormodels/reports/cma_diagnostics.py +646 -0
  81. factormodels-0.1.0/src/factormodels/reports/cma_inference.py +993 -0
  82. factormodels-0.1.0/src/factormodels/reports/covariance.py +210 -0
  83. factormodels-0.1.0/src/factormodels/reports/tests/__init__.py +1 -0
  84. factormodels-0.1.0/src/factormodels/reports/tests/cma_diagnostics_test.py +344 -0
  85. factormodels-0.1.0/src/factormodels/reports/tests/cma_inference_test.py +459 -0
  86. factormodels-0.1.0/src/factormodels/risk.py +99 -0
  87. factormodels-0.1.0/src/factormodels/signals.py +97 -0
  88. factormodels-0.1.0/src/factormodels/spec.py +636 -0
  89. factormodels-0.1.0/src/factormodels/tests/_estimation_fixture.py +34 -0
  90. factormodels-0.1.0/src/factormodels/tests/bundle_test.py +304 -0
  91. factormodels-0.1.0/src/factormodels/tests/construction_test.py +316 -0
  92. factormodels-0.1.0/src/factormodels/tests/estimation/__init__.py +1 -0
  93. factormodels-0.1.0/src/factormodels/tests/estimation/test_cadence_penalty.py +151 -0
  94. factormodels-0.1.0/src/factormodels/tests/estimation/test_cluster_smoothing.py +245 -0
  95. factormodels-0.1.0/src/factormodels/tests/estimation/test_covar_reporting.py +287 -0
  96. factormodels-0.1.0/src/factormodels/tests/estimation/test_derived_signs.py +147 -0
  97. factormodels-0.1.0/src/factormodels/tests/estimation/test_factor_clustering.py +262 -0
  98. factormodels-0.1.0/src/factormodels/tests/estimation/test_factor_estimator_guards.py +389 -0
  99. factormodels-0.1.0/src/factormodels/tests/estimation/test_native_factor.py +32 -0
  100. factormodels-0.1.0/src/factormodels/tests/estimation/test_residual_covariance.py +260 -0
  101. factormodels-0.1.0/src/factormodels/tests/estimation/test_risk_export.py +105 -0
  102. factormodels-0.1.0/src/factormodels/tests/examples_test.py +124 -0
  103. factormodels-0.1.0/src/factormodels/tests/package_identity_test.py +14 -0
  104. factormodels-0.1.0/src/factormodels/tests/portfolio_context_test.py +75 -0
  105. factormodels-0.1.0/src/factormodels/tests/signals_test.py +183 -0
  106. factormodels-0.1.0/src/factormodels.egg-info/PKG-INFO +595 -0
  107. factormodels-0.1.0/src/factormodels.egg-info/SOURCES.txt +129 -0
  108. factormodels-0.1.0/src/factormodels.egg-info/dependency_links.txt +1 -0
  109. factormodels-0.1.0/src/factormodels.egg-info/requires.txt +12 -0
  110. factormodels-0.1.0/src/factormodels.egg-info/top_level.txt +1 -0
  111. factormodels-0.1.0/tests/parity/consumer_manifest.json +173 -0
  112. factormodels-0.1.0/tests/parity/manifest.json +97 -0
  113. factormodels-0.1.0/tests/parity/test_replay_reference.py +207 -0
  114. factormodels-0.1.0/tests/synthetic_data.py +16 -0
  115. factormodels-0.1.0/tests/test_bundle_load.py +2 -0
  116. factormodels-0.1.0/tests/test_construction_parity.py +40 -0
  117. factormodels-0.1.0/tests/test_core_api.py +31 -0
  118. factormodels-0.1.0/tests/test_cutoff.py +81 -0
  119. factormodels-0.1.0/tests/test_dependency_floor.py +53 -0
  120. factormodels-0.1.0/tests/test_documented_contracts.py +176 -0
  121. factormodels-0.1.0/tests/test_estimation_parity.py +96 -0
  122. factormodels-0.1.0/tests/test_examples.py +146 -0
  123. factormodels-0.1.0/tests/test_gls_cma.py +49 -0
  124. factormodels-0.1.0/tests/test_navigation_refs.py +89 -0
  125. factormodels-0.1.0/tests/test_readme.py +93 -0
  126. factormodels-0.1.0/tests/test_reports.py +33 -0
  127. factormodels-0.1.0/tests/test_risk_export.py +112 -0
  128. factormodels-0.1.0/tools/check_navigation_refs.py +106 -0
  129. factormodels-0.1.0/tools/navigation_refs.json +5 -0
  130. factormodels-0.1.0/tools/replay_reference.py +539 -0
  131. 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