Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Guidance for Claude Code sessions working in this repository.
**jquantstats** — portfolio analytics for quants, built on [Polars](https://pola.rs/)
(zero pandas at runtime) with interactive [Plotly](https://plotly.com/python/) charts.
Python `>=3.11`, MIT-licensed, published to PyPI. This is a
[Rhiza](https://github.com/jebel-quant/rhiza)-managed repository (template `v1.1.2`).
[Rhiza](https://github.com/jebel-quant/rhiza)-managed repository (template `v1.2.0`).

## Commands

Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -390,6 +390,11 @@ categorized metric tables, rendered via Jinja2 templates.

For detailed documentation, visit [jQuantStats Documentation](https://jebel-quant.github.io/jquantstats).

The public API (`Portfolio` and `Data`) follows [Semantic Versioning](https://semver.org/)
from **v1.0.0** onwards; see the
[API Stability & deprecation policy](https://jebel-quant.github.io/jquantstats/STABILITY/)
for the exact stability guarantee and deprecation timeline.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.
Expand Down
8 changes: 8 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,11 @@ ignore-init-method = true
ignore-magic = true
ignore-overloaded-functions = true

# Test-layout parity (rhiza check_test_layout): tests here are organised by
# behaviour under tests/test_jquantstats/… rather than mirroring src/ 1:1, and
# per-module coverage is guaranteed by the 100% line+branch pytest gate above
# (a stronger guarantee than file-mirroring). Opt out of the 1:1 mirror rule.
[tool.check_test_layout]
enforce = false
reason = "Tests are organised by behaviour under tests/test_jquantstats/; per-module coverage is guaranteed by the 100% pytest coverage gate rather than 1:1 file mirroring."

6 changes: 2 additions & 4 deletions src/jquantstats/_portfolio_cost.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@

import math

import numpy as np
import polars as pl

from ._portfolio_base import _PortfolioMembers
from ._stats._core import _std_is_negligible
from .exceptions import InvalidMaxBpsError, NegativeCostBpsError


Expand Down Expand Up @@ -181,10 +183,6 @@ def trading_cost_impact(self, max_bps: int = 20) -> pl.DataFrame:
"""
if not isinstance(max_bps, int) or max_bps < 1:
raise InvalidMaxBpsError(max_bps)
import numpy as np

from ._stats._core import _std_is_negligible

periods = self.data._periods_per_year # one Data object, outside the loop
sqrt_periods = float(np.sqrt(periods))
cost_levels = list(range(max_bps + 1))
Expand Down
6 changes: 6 additions & 0 deletions src/jquantstats/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,9 @@ def plots(self) -> DataPlots:
DataPlots: An instance of the DataPlots class initialized with this data.

"""
# Deferred to break the data <-> accessors import cycle: _plots imports
# DataLike from this module, so hoisting this to module top re-forms the
# cycle. Keep the import local.
Comment on lines +523 to +525
from ._plots import DataPlots

return DataPlots(self)
Expand All @@ -532,6 +535,7 @@ def stats(self) -> Stats:
Stats: An instance of the Stats class initialized with this data.

"""
# Deferred to break the data <-> accessors import cycle (see .plots).
from ._stats import Stats

return Stats(self)
Expand All @@ -544,6 +548,7 @@ def reports(self) -> Reports:
Reports: An instance of the Reports class initialized with this data.

"""
# Deferred to break the data <-> accessors import cycle (see .plots).
from ._reports import Reports

return Reports(self)
Expand All @@ -556,6 +561,7 @@ def utils(self) -> DataUtils:
DataUtils: An instance of the DataUtils class initialized with this data.

"""
# Deferred to break the data <-> accessors import cycle (see .plots).
from ._utils import DataUtils

return DataUtils(self)
Expand Down
Loading