riskkit-quant 0.4.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 (53) hide show
  1. riskkit_quant-0.4.0/.github/ISSUE_TEMPLATE/bug_report.md +21 -0
  2. riskkit_quant-0.4.0/.github/ISSUE_TEMPLATE/feature_request.md +18 -0
  3. riskkit_quant-0.4.0/.github/pull_request_template.md +10 -0
  4. riskkit_quant-0.4.0/.github/workflows/ci.yml +26 -0
  5. riskkit_quant-0.4.0/.github/workflows/release.yml +28 -0
  6. riskkit_quant-0.4.0/.gitignore +25 -0
  7. riskkit_quant-0.4.0/CHANGELOG.md +101 -0
  8. riskkit_quant-0.4.0/CONTRIBUTING.md +42 -0
  9. riskkit_quant-0.4.0/LICENSE +21 -0
  10. riskkit_quant-0.4.0/PKG-INFO +260 -0
  11. riskkit_quant-0.4.0/PUBLISHING.md +62 -0
  12. riskkit_quant-0.4.0/README.md +221 -0
  13. riskkit_quant-0.4.0/ROADMAP.md +68 -0
  14. riskkit_quant-0.4.0/docs/components.md +93 -0
  15. riskkit_quant-0.4.0/docs/index.md +44 -0
  16. riskkit_quant-0.4.0/docs/integrations.md +112 -0
  17. riskkit_quant-0.4.0/docs/quickstart.md +111 -0
  18. riskkit_quant-0.4.0/examples/backtesting_py_strategy.py +61 -0
  19. riskkit_quant-0.4.0/examples/backtesting_riskmanager.py +46 -0
  20. riskkit_quant-0.4.0/examples/freqtrade_callbacks.py +58 -0
  21. riskkit_quant-0.4.0/examples/multi_asset_book.py +102 -0
  22. riskkit_quant-0.4.0/examples/pipeline.py +60 -0
  23. riskkit_quant-0.4.0/examples/risk_manager.py +76 -0
  24. riskkit_quant-0.4.0/examples/vectorbt_sizing.py +45 -0
  25. riskkit_quant-0.4.0/mkdocs.yml +33 -0
  26. riskkit_quant-0.4.0/pyproject.toml +54 -0
  27. riskkit_quant-0.4.0/src/riskkit/__init__.py +86 -0
  28. riskkit_quant-0.4.0/src/riskkit/adapters/__init__.py +7 -0
  29. riskkit_quant-0.4.0/src/riskkit/adapters/backtesting.py +165 -0
  30. riskkit_quant-0.4.0/src/riskkit/adapters/freqtrade.py +144 -0
  31. riskkit_quant-0.4.0/src/riskkit/adapters/vectorbt.py +129 -0
  32. riskkit_quant-0.4.0/src/riskkit/correlation.py +119 -0
  33. riskkit_quant-0.4.0/src/riskkit/drawdown.py +171 -0
  34. riskkit_quant-0.4.0/src/riskkit/manager.py +619 -0
  35. riskkit_quant-0.4.0/src/riskkit/metrics.py +41 -0
  36. riskkit_quant-0.4.0/src/riskkit/py.typed +0 -0
  37. riskkit_quant-0.4.0/src/riskkit/session.py +173 -0
  38. riskkit_quant-0.4.0/src/riskkit/sizing.py +263 -0
  39. riskkit_quant-0.4.0/src/riskkit/stops.py +228 -0
  40. riskkit_quant-0.4.0/src/riskkit/validator.py +197 -0
  41. riskkit_quant-0.4.0/tests/test_adapter_backtesting.py +56 -0
  42. riskkit_quant-0.4.0/tests/test_adapter_freqtrade.py +77 -0
  43. riskkit_quant-0.4.0/tests/test_adapter_vectorbt.py +49 -0
  44. riskkit_quant-0.4.0/tests/test_correlation.py +34 -0
  45. riskkit_quant-0.4.0/tests/test_drawdown.py +84 -0
  46. riskkit_quant-0.4.0/tests/test_manager.py +310 -0
  47. riskkit_quant-0.4.0/tests/test_metrics.py +46 -0
  48. riskkit_quant-0.4.0/tests/test_presets.py +73 -0
  49. riskkit_quant-0.4.0/tests/test_properties.py +207 -0
  50. riskkit_quant-0.4.0/tests/test_session.py +57 -0
  51. riskkit_quant-0.4.0/tests/test_sizing.py +155 -0
  52. riskkit_quant-0.4.0/tests/test_stops.py +120 -0
  53. riskkit_quant-0.4.0/tests/test_validator.py +88 -0
@@ -0,0 +1,21 @@
1
+ ---
2
+ name: Bug report
3
+ about: Something behaves differently than documented
4
+ title: "[bug] "
5
+ labels: bug
6
+ ---
7
+
8
+ **What happened**
9
+ A clear description of the bug.
10
+
11
+ **Minimal repro**
12
+ ```python
13
+ # the smallest snippet that shows it
14
+ ```
15
+
16
+ **Expected vs actual**
17
+ What you expected, and what happened instead.
18
+
19
+ **Environment**
20
+ - riskkit version:
21
+ - Python version:
@@ -0,0 +1,18 @@
1
+ ---
2
+ name: Feature request
3
+ about: Suggest a new rule, component, or integration
4
+ title: "[feature] "
5
+ labels: enhancement
6
+ ---
7
+
8
+ **The risk problem this solves**
9
+ What gap or failure mode are you trying to guard against?
10
+
11
+ **Proposed API**
12
+ Roughly how would it look to call this?
13
+
14
+ **Alternatives**
15
+ Anything you've tried or considered.
16
+
17
+ **Scope check**
18
+ Does this stay framework-agnostic and anti-martingale? (See CONTRIBUTING.md.)
@@ -0,0 +1,10 @@
1
+ ## What this changes
2
+
3
+ Briefly, what and why.
4
+
5
+ ## Checklist
6
+
7
+ - [ ] Tests added/updated and `pytest` passes locally
8
+ - [ ] Public API has docstrings
9
+ - [ ] `CHANGELOG.md` updated
10
+ - [ ] Stays framework-agnostic and anti-martingale (see CONTRIBUTING.md)
@@ -0,0 +1,26 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ["3.9", "3.10", "3.11", "3.12"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+ - name: Set up Python ${{ matrix.python-version }}
18
+ uses: actions/setup-python@v5
19
+ with:
20
+ python-version: ${{ matrix.python-version }}
21
+ - name: Install
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ pip install -e ".[dev]"
25
+ - name: Run tests
26
+ run: pytest -v
@@ -0,0 +1,28 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publishes when you push a version tag like v0.2.0.
4
+ # Uses PyPI Trusted Publishing (OIDC) — no API token stored in the repo.
5
+ # One-time setup: on pypi.org add a "pending publisher" for project `riskkit`,
6
+ # owner `HasibDaddy`, repo `riskkit`, workflow `release.yml`, environment `pypi`.
7
+
8
+ on:
9
+ push:
10
+ tags: ["v*"]
11
+
12
+ jobs:
13
+ build-and-publish:
14
+ runs-on: ubuntu-latest
15
+ environment: pypi
16
+ permissions:
17
+ id-token: write # required for trusted publishing
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+ - uses: actions/setup-python@v5
21
+ with:
22
+ python-version: "3.12"
23
+ - name: Build
24
+ run: |
25
+ python -m pip install --upgrade build
26
+ python -m build
27
+ - name: Publish
28
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,25 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+ build/
7
+ dist/
8
+ .venv/
9
+ venv/
10
+
11
+ # Tooling
12
+ .pytest_cache/
13
+ .mypy_cache/
14
+ .ruff_cache/
15
+ .hypothesis/
16
+ .coverage
17
+ htmlcov/
18
+
19
+ # Docs build output (mkdocs)
20
+ site/
21
+
22
+ # OS / editor
23
+ .DS_Store
24
+ .idea/
25
+ .vscode/
@@ -0,0 +1,101 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. This project adheres to
4
+ [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.4.0] - 2026-06-23
9
+
10
+ ### Added
11
+ - Three more **stops** in the `StopEngine` stack: **chandelier** (trails ATR from
12
+ the highest high / lowest low since entry — `StopStack(use_chandelier=True)`,
13
+ `StopEngine(chandelier_atr_multiplier=...)`), **structure** (ratchets to a swing
14
+ level you pass as `update(..., structure_level=...)`), and **PSAR** (ratchets to a
15
+ Parabolic SAR value you pass as `update(..., psar_value=...)`). All tighten-only;
16
+ `update()` gained optional `current_high` / `current_low` for the chandelier extreme.
17
+ - Standalone, composable **sizers** (pure functions): `kelly_fraction()` (edge-optimal
18
+ risk fraction, `fraction=0.5` for half-Kelly), `volatility_target_size()` (size a
19
+ position to a target volatility, notional-capped), and `inverse_vol_weights()` (naive
20
+ risk-parity weights ∝ 1/σ). `PositionSizer` now delegates its half-Kelly ceiling to
21
+ `kelly_fraction` (single source of truth).
22
+ - Portfolio-level **heat** cap — `RiskConfig(max_portfolio_heat_pct=...)` limits the
23
+ total capital at risk across open positions (Σ units × distance-to-stop), checked
24
+ by the validator and surfaced via `RiskManager.portfolio_heat_pct()`. Off by
25
+ default; the presets set it (conservative 4% / balanced 8% / aggressive 15%).
26
+ - Per-sector / asset-class **exposure** cap — `RiskConfig(max_exposure_per_sector_pct=...)`
27
+ keeps any one sector from dominating the book. Tag trades with `TradeIntent(sector=...)`;
28
+ the manager tracks open notional per sector (`RiskManager.sector_exposure_pct(sector)`
29
+ and `.sector_exposure()`) and the validator blocks an entry that would push its sector
30
+ over the cap. Untagged trades are never capped. Off by default; the presets set it
31
+ (conservative 4% / balanced 10% / aggressive 25%).
32
+ - Property-based tests (hypothesis) for the core invariants: a position never
33
+ exceeds its notional/risk caps, size never increases after losses or deeper
34
+ drawdown (anti-martingale), the per-sector exposure cap is never breached across
35
+ random fill sequences, and the standalone sizers stay within bounds (vol-target
36
+ ≤ notional cap and falls as vol rises; inverse-vol weights sum to 1; Kelly within
37
+ `[0, fraction]` and rising with edge).
38
+ - `value_at_risk` / `conditional_value_at_risk` — historical VaR and expected
39
+ shortfall over a return series (positive loss magnitudes; CVaR ≥ VaR by
40
+ construction).
41
+
42
+ ## [0.3.0] - 2026-06-22
43
+
44
+ ### Added
45
+ - `RiskManager` façade — wires all six components from a single `RiskConfig` and
46
+ turns one `TradeIntent` into a sized, validated `RiskDecision` in a single
47
+ `evaluate()` call. Tracks drawdown, session, and open-book state for you via
48
+ `on_equity()` / `on_fill()` / `on_close()`. See `examples/risk_manager.py`.
49
+ - backtesting.py adapter — `riskkit.adapters.backtesting.RiskkitStrategy`, a
50
+ `Strategy` mixin whose `risk_long()` / `risk_short()` size and validate every
51
+ entry through a `RiskManager` and feed closed trades back to the session. New
52
+ `backtesting` optional extra; see `examples/backtesting_riskmanager.py`.
53
+ - `RiskConfig` presets (`conservative` / `balanced` / `aggressive`, plus
54
+ `RiskConfig.preset(name)`) and loaders — `RiskConfig.from_dict()`,
55
+ `RiskConfig.to_dict()`, and `RiskConfig.from_yaml()` (new `yaml` extra).
56
+ - freqtrade adapter — `riskkit.adapters.freqtrade.FreqtradeRiskManager`, which
57
+ drives `custom_stake_amount` / `confirm_trade_entry` from a `RiskManager`
58
+ (framework-agnostic: it imports nothing from freqtrade).
59
+ - vectorbt adapter — `riskkit.adapters.vectorbt.size_signals`, which sizes an
60
+ array of entry signals with riskkit for `Portfolio.from_signals`.
61
+ - Runnable integration examples for backtesting.py and freqtrade.
62
+ - mkdocs documentation site (Home / Quickstart / Components / Integrations).
63
+ - PyPI trusted-publishing release workflow and `PUBLISHING.md` guide.
64
+
65
+ ### Fixed
66
+ - `PositionSizer` now reports `risk_pct` consistent with `risk_amount` when the
67
+ notional cap binds (previously `risk_pct` kept the pre-cap target while
68
+ `risk_amount` reflected the smaller, capped position).
69
+
70
+ ## [0.2.0] - 2026-06-19
71
+
72
+ ### Added
73
+ - `StopEngine` / `StopStack` — composable per-position stop stack (initial,
74
+ break-even, ATR-trailing, EMA-trailing, time, and volatility stops); tightest
75
+ stop wins and stops only ever move closer.
76
+ - `CorrelationGuard` — one open position per correlation group, from static
77
+ groups and/or a dynamically computed return-correlation matrix (pandas extra).
78
+ - `SessionManager` — daily trade/loss caps, profit-taking stops, minimum
79
+ spacing, escalating cooldowns, and tilt detection.
80
+ - `PreTradeValidator` — composable final-gate checklist across market quality,
81
+ sizing, risk limits, signal quality, and timing; returns a result per check.
82
+ - `examples/pipeline.py` end-to-end demo, contribution guide, and issue/PR
83
+ templates.
84
+
85
+ ### Changed
86
+ - Generalized the API to be framework-agnostic (e.g. `symbol`/`score` instead of
87
+ exchange-specific names; correlation groups and regime maps are now injected
88
+ rather than hardcoded).
89
+
90
+ ## [0.1.0] - 2026-06-19
91
+
92
+ Initial release.
93
+
94
+ ### Added
95
+ - `PositionSizer` — volatility-adjusted fixed-fractional position sizing with a
96
+ half-Kelly ceiling, a reduction ladder (losing streaks, drawdown tiers, daily
97
+ loss), a high-conviction bonus, and a hard notional cap. Every adjustment is
98
+ returned for auditing.
99
+ - `DrawdownManager` — high-water-mark drawdown tracking with a 5-tier ladder, a
100
+ one-step-at-a-time recovery ramp, and a rolling weekly-loss pause.
101
+ - Full type hints (`py.typed`) and a test suite covering both modules.
@@ -0,0 +1,42 @@
1
+ # Contributing to riskkit
2
+
3
+ Thanks for your interest. riskkit aims to be the dependable, framework-agnostic
4
+ risk layer for systematic trading — correctness and clarity matter more than
5
+ features.
6
+
7
+ ## Dev setup
8
+
9
+ ```bash
10
+ git clone https://github.com/HasibDaddy/riskkit
11
+ cd riskkit
12
+ python -m venv .venv && source .venv/bin/activate
13
+ pip install -e ".[dev]"
14
+ pytest
15
+ ```
16
+
17
+ ## Principles (please keep these)
18
+
19
+ - **No framework lock-in.** The core must not depend on any exchange SDK, data
20
+ provider, or backtesting framework. Heavy optional deps (like pandas) go
21
+ behind an extra and are imported lazily.
22
+ - **Every decision is auditable.** New rules should return *why* they fired, not
23
+ just a boolean.
24
+ - **Conservative defaults.** Floors, ceilings, and caps bound every knob.
25
+ - **Anti-martingale only.** Nothing in this library may increase risk after a
26
+ loss.
27
+
28
+ ## Pull requests
29
+
30
+ 1. Add or update tests — every behaviour change needs a test.
31
+ 2. Keep the public API documented (docstrings render in the README examples).
32
+ 3. Run `pytest` locally; CI runs the suite on Python 3.9–3.12.
33
+ 4. Update `CHANGELOG.md` under an `## [Unreleased]` heading.
34
+
35
+ ## Good first contributions
36
+
37
+ - Integration examples/adapters for a specific framework (backtesting.py,
38
+ vectorbt, freqtrade).
39
+ - A worked notebook walking through one component on real OHLCV data.
40
+ - Edge-case tests for the existing modules.
41
+
42
+ Open an issue to discuss anything larger before you build it.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hasib
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,260 @@
1
+ Metadata-Version: 2.4
2
+ Name: riskkit-quant
3
+ Version: 0.4.0
4
+ Summary: A framework-agnostic risk-management toolkit for systematic traders: position sizing, drawdown laddering, and more.
5
+ Project-URL: Homepage, https://github.com/HasibDaddy/riskkit
6
+ Project-URL: Repository, https://github.com/HasibDaddy/riskkit
7
+ Project-URL: Issues, https://github.com/HasibDaddy/riskkit/issues
8
+ Author: Hasib
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: algotrading,backtesting,drawdown,kelly-criterion,position-sizing,quant,risk-management,trading
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: Financial and Insurance Industry
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.9
18
+ Classifier: Programming Language :: Python :: 3.10
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Topic :: Office/Business :: Financial :: Investment
22
+ Classifier: Typing :: Typed
23
+ Requires-Python: >=3.9
24
+ Provides-Extra: backtesting
25
+ Requires-Dist: backtesting>=0.3; extra == 'backtesting'
26
+ Provides-Extra: dev
27
+ Requires-Dist: backtesting>=0.3; extra == 'dev'
28
+ Requires-Dist: hypothesis>=6.0; extra == 'dev'
29
+ Requires-Dist: pandas>=1.0; extra == 'dev'
30
+ Requires-Dist: pytest>=7.0; extra == 'dev'
31
+ Requires-Dist: pyyaml>=5.0; extra == 'dev'
32
+ Provides-Extra: docs
33
+ Requires-Dist: mkdocs-material>=9.0; extra == 'docs'
34
+ Provides-Extra: pandas
35
+ Requires-Dist: pandas>=1.0; extra == 'pandas'
36
+ Provides-Extra: yaml
37
+ Requires-Dist: pyyaml>=5.0; extra == 'yaml'
38
+ Description-Content-Type: text/markdown
39
+
40
+ # riskkit
41
+
42
+ [![CI](https://github.com/HasibDaddy/riskkit/actions/workflows/ci.yml/badge.svg)](https://github.com/HasibDaddy/riskkit/actions/workflows/ci.yml)
43
+ [![Docs](https://img.shields.io/badge/docs-mkdocs-1f6feb)](https://hasibdaddy.github.io/riskkit/)
44
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
45
+ ![Python](https://img.shields.io/badge/python-3.9%E2%80%933.12-blue.svg)
46
+ ![Dependencies](https://img.shields.io/badge/runtime%20deps-0-brightgreen.svg)
47
+
48
+ **A framework-agnostic risk-management toolkit for systematic traders.**
49
+
50
+ Most open-source trading tools focus on the fun part — signals, indicators,
51
+ backtesting engines. They leave the part that actually decides whether you
52
+ survive thin or absent: *how big a position to take, when to cut size, and when
53
+ to stop trading altogether.* That's what blows up retail algo traders, not a
54
+ bad entry signal.
55
+
56
+ `riskkit` is that missing layer. The components are pure Python with **no
57
+ dependency on any exchange, data provider, or backtesting framework**. They
58
+ don't know what CCXT is. You feed them numbers; they hand back decisions you can
59
+ audit. Drop them into [backtesting.py](https://github.com/kernc/backtesting.py),
60
+ [vectorbt](https://github.com/polakowo/vectorbt), [backtrader](https://github.com/mementum/backtrader),
61
+ [freqtrade](https://github.com/freqtrade/freqtrade), or your own loop.
62
+
63
+ > ⚠️ **Not financial advice.** `riskkit` helps you *implement* a risk policy you
64
+ > have chosen. It does not choose one for you, and it cannot make a losing
65
+ > strategy profitable. Test everything on paper first.
66
+
67
+ ---
68
+
69
+ ## Install
70
+
71
+ ```bash
72
+ pip install "git+https://github.com/HasibDaddy/riskkit.git"
73
+ ```
74
+
75
+ Zero runtime dependencies. Python 3.9+. *(A PyPI release is on the way — until
76
+ then, install straight from GitHub with the line above.)*
77
+
78
+ ---
79
+
80
+ ## What's in the box
81
+
82
+ | Component | What it does |
83
+ |---|---|
84
+ | `PositionSizer` | Volatility-adjusted fixed-fractional sizing with an optional half-Kelly ceiling, a reduction ladder for losing streaks / drawdowns, and a hard notional cap. |
85
+ | `DrawdownManager` | Tracks high-water-mark drawdown, maps it onto a tier ladder (cut size → raise the bar → halt), with a recovery ramp and a rolling weekly-loss pause. |
86
+ | `StopEngine` | A composable stop *stack* per position — initial, break-even, ATR/EMA trailing, chandelier, structure (swing), PSAR, time, and volatility stops. The tightest one wins; stops only ever move closer. |
87
+ | `CorrelationGuard` | At most one open position per correlation group. Groups can be static (you define them) or computed dynamically from a rolling return-correlation matrix. |
88
+ | `SessionManager` | Daily trade/loss caps, profit-taking stops, minimum spacing, escalating cooldowns after losing streaks, and tilt detection. |
89
+ | `PreTradeValidator` | The composable final gate: runs every rule against a proposed trade and vetoes it if any fails — returning exactly which checks passed and failed. |
90
+
91
+ Every decision is **auditable** — the sizer returns which multipliers fired,
92
+ the stop engine logs each adjustment, and the validator returns a pass/fail line
93
+ for every single check.
94
+
95
+ Beyond the six components, riskkit ships a few **portfolio-level controls** and
96
+ **standalone sizers** you can reach for on their own:
97
+
98
+ - **Portfolio caps** (enforced by `RiskManager` as the book fills): total open
99
+ notional, total **heat** (risk-at-stop), and **per-sector / asset-class**
100
+ exposure — so no single sector can dominate the book.
101
+ - **Composable sizers** (pure functions): `volatility_target_size`,
102
+ `inverse_vol_weights` (naive risk parity), and `kelly_fraction`.
103
+ - **Risk metrics**: historical `value_at_risk` and `conditional_value_at_risk`.
104
+
105
+ ---
106
+
107
+ ## Quick start
108
+
109
+ ### The whole stack, one call
110
+
111
+ `RiskManager` is the façade: wire all six components from a single config, push
112
+ equity in as your account moves, and ask one question per trade. It keeps the
113
+ drawdown, session, and open-position state in sync for you.
114
+
115
+ ```python
116
+ from riskkit import RiskManager, RiskConfig, TradeIntent
117
+
118
+ risk = RiskManager(RiskConfig(
119
+ base_risk_pct=1.0, max_notional_pct=4.0,
120
+ drawdown=dict(tier1_pct=3, halt_pct=10),
121
+ session=dict(max_trades_per_day=5),
122
+ correlation=dict(static_groups={"majors": {"BTC/USDT", "ETH/USDT"}}),
123
+ ))
124
+
125
+ risk.on_equity(10_000) # refresh drawdown/session state
126
+ decision = risk.evaluate(TradeIntent(
127
+ symbol="BTC/USDT", side="long",
128
+ entry_price=100.0, stop_price=98.0, target_price=104.0,
129
+ score=82, atr=2.0, atr_baseline=2.0,
130
+ ))
131
+
132
+ if decision.ok:
133
+ place(decision.units, decision.stop) # your execution layer
134
+ risk.on_fill(decision) # tell riskkit it filled
135
+ else:
136
+ print("skip:", *decision.reasons, sep="\n ") # every gate that vetoed it
137
+ ```
138
+
139
+ Reach past the façade to any single component when you need to — they're all
140
+ exposed (`risk.sizer`, `risk.drawdown`, `risk.stops`, …) and usable standalone.
141
+
142
+ Don't want to tune every knob? Start from a preset, or load policy from YAML:
143
+
144
+ ```python
145
+ risk = RiskManager(RiskConfig.conservative()) # or .balanced() / .aggressive()
146
+ cfg = RiskConfig.from_yaml("risk.yaml") # needs riskkit[yaml]
147
+ ```
148
+
149
+ ### Sizing a trade
150
+
151
+ ```python
152
+ from riskkit import PositionSizer, SizingInputs
153
+
154
+ sizer = PositionSizer(
155
+ base_risk_pct=1.0, # risk 1% of equity per trade, before adjustments
156
+ max_risk_pct=1.5, # never risk more than 1.5%
157
+ max_notional_pct=4.0, # never let a position exceed 4% of equity
158
+ )
159
+
160
+ result = sizer.size(SizingInputs(
161
+ equity=10_000,
162
+ entry_price=100.0,
163
+ stop_price=98.0, # the stop distance defines your risk per unit
164
+ atr=2.5, # current volatility
165
+ atr_baseline=2.0, # "normal" volatility -> scales risk down when choppy
166
+ consecutive_losses=2, # reduction ladder kicks in
167
+ drawdown_pct=4.0,
168
+ ))
169
+
170
+ if result.units > 0:
171
+ print(f"Buy {result.units:.4f} units (risk {result.risk_pct:.2%})")
172
+ print("adjustments:", result.multipliers_applied)
173
+ else:
174
+ print("Skip:", result.reason_for_zero)
175
+ ```
176
+
177
+ ### Adapting to drawdown
178
+
179
+ ```python
180
+ from riskkit import DrawdownManager
181
+
182
+ dm = DrawdownManager(tier1_pct=3, tier2_pct=5, tier3_pct=7, halt_pct=10)
183
+
184
+ state = dm.update(current_equity) # call once per equity refresh
185
+ if state.halted:
186
+ print("No new trades:", state.reason)
187
+ else:
188
+ size = base_size * state.size_multiplier # scale every position by the tier
189
+ ```
190
+
191
+ The two compose naturally: feed `DrawdownManager`'s `drawdown_pct` and
192
+ `size_multiplier` straight into the sizer.
193
+
194
+ ---
195
+
196
+ ## Design principles
197
+
198
+ - **Framework-agnostic.** No exchange SDK, no pandas requirement in the core,
199
+ no global state. Just dataclasses in, dataclasses out.
200
+ - **Auditable, not magic.** Every adjustment is named and returned. You can log
201
+ the exact reason a trade was sized down or skipped.
202
+ - **Conservative by default.** Floors, ceilings, and hard caps bound every knob.
203
+ The math can recommend; it can never exceed the limits you set.
204
+ - **Anti-martingale.** Size goes *down* after losses and during drawdowns, never
205
+ up. There is no "average down" path anywhere in this library.
206
+
207
+ ---
208
+
209
+ ## Integrations
210
+
211
+ riskkit slots into whatever you already use — the [examples](examples/) are
212
+ runnable:
213
+
214
+ - **backtesting.py** — subclass the `RiskkitStrategy` adapter
215
+ (`from riskkit.adapters.backtesting import RiskkitStrategy`) and call
216
+ `risk_long()` / `risk_short()`; every entry is sized **and** validated by one
217
+ `RiskConfig`, with closed trades fed back to the session manager. See
218
+ [`examples/backtesting_riskmanager.py`](examples/backtesting_riskmanager.py)
219
+ (full façade) or [`examples/backtesting_py_strategy.py`](examples/backtesting_py_strategy.py)
220
+ (just `PositionSizer`, by hand).
221
+ - **freqtrade** — `FreqtradeRiskManager`
222
+ (`from riskkit.adapters.freqtrade import FreqtradeRiskManager`) drives
223
+ `custom_stake_amount` + `confirm_trade_entry` from one `RiskConfig`; see
224
+ [`examples/freqtrade_callbacks.py`](examples/freqtrade_callbacks.py).
225
+ - **vectorbt** — `size_signals`
226
+ (`from riskkit.adapters.vectorbt import size_signals`) turns entry signals into
227
+ a riskkit-sized array for `Portfolio.from_signals`; see
228
+ [`examples/vectorbt_sizing.py`](examples/vectorbt_sizing.py).
229
+ - **your own loop** — [`examples/risk_manager.py`](examples/risk_manager.py)
230
+ drives the full `RiskManager` façade end-to-end;
231
+ [`examples/multi_asset_book.py`](examples/multi_asset_book.py) allocates,
232
+ vol-targets, and vets a cross-sector book through the portfolio caps;
233
+ [`examples/pipeline.py`](examples/pipeline.py) shows the same flow wired by hand.
234
+
235
+ 📖 **Full docs: https://hasibdaddy.github.io/riskkit/**
236
+
237
+ ## Roadmap
238
+
239
+ `riskkit` is extracted and generalized from a working risk-first trading bot.
240
+ The core six components are in place; next up is making them effortless to drop
241
+ into the popular frameworks:
242
+
243
+ - [x] `PositionSizer`, `DrawdownManager`, `StopEngine`
244
+ - [x] `CorrelationGuard`, `SessionManager`, `PreTradeValidator`
245
+ - [x] A single `RiskManager` façade that wires all six together with one config
246
+ - [x] Config presets (conservative / balanced / aggressive) + dict/YAML loading
247
+ - [x] First-class adapters for backtesting.py, freqtrade, and vectorbt
248
+ - [x] A [hosted docs site](https://hasibdaddy.github.io/riskkit/) with component recipes
249
+ - [x] Portfolio caps (total-exposure, heat, per-sector) + standalone sizers (vol-target, risk-parity, Kelly) + VaR/CVaR
250
+ - [ ] A PyPI release (`pip install riskkit-quant`, then `import riskkit`)
251
+
252
+ Feedback on the API is genuinely welcome — open an issue. See the full
253
+ [ROADMAP.md](ROADMAP.md), [CONTRIBUTING.md](CONTRIBUTING.md), and the
254
+ [examples](examples/).
255
+
256
+ ---
257
+
258
+ ## License
259
+
260
+ MIT © 2026 Hasib. See [LICENSE](LICENSE).
@@ -0,0 +1,62 @@
1
+ # Publishing riskkit to PyPI
2
+
3
+ **Status (2026-06-23):** v0.4.0 is **build-verified and ready to publish** —
4
+ `python -m build` succeeds, `twine check` passes, and a clean-venv install of the
5
+ wheel imports and runs the full v0.4 surface (core is zero-dependency). The only
6
+ steps left are the PyPI-account ones below.
7
+
8
+ **Distribution name:** `riskkit-quant`. The ideal `riskkit` is unregistered (API
9
+ 404) but PyPI's pending-publisher form rejects it as **too similar to the existing
10
+ `risk-kit`**, and `riskkit-trading` was also rejected. The accepted name is
11
+ `riskkit-quant` (free, distinct). The *import* name is unchanged:
12
+ `pip install riskkit-quant` then `import riskkit` — exactly like `scikit-learn` →
13
+ `import sklearn`. Never re-upload a version once published.
14
+
15
+ Two ways to publish — the automated one (recommended) and the manual one.
16
+
17
+ ## Recommended: Trusted Publishing (no tokens)
18
+
19
+ This uses the included `.github/workflows/release.yml`. You configure PyPI once
20
+ to trust your GitHub repo, then publishing is just pushing a tag.
21
+
22
+ 1. Create a PyPI account at https://pypi.org and verify your email.
23
+ 2. Go to **Your projects → Publishing → Add a pending publisher** and enter:
24
+ - PyPI project name: `riskkit-quant`
25
+ - Owner: `HasibDaddy`
26
+ - Repository name: `riskkit`
27
+ - Workflow name: `release.yml`
28
+ - Environment name: `pypi`
29
+ 3. In your GitHub repo, create an environment named `pypi`
30
+ (Settings → Environments → New environment).
31
+ 4. Tag and push a release:
32
+ ```bash
33
+ git tag v0.4.0
34
+ git push origin v0.4.0
35
+ ```
36
+ The workflow builds the package and publishes it. Done.
37
+
38
+ ## Manual (one machine, with a token)
39
+
40
+ ```bash
41
+ python -m pip install --upgrade build twine
42
+ python -m build # creates dist/*.whl and dist/*.tar.gz
43
+ python -m twine check dist/*
44
+ python -m twine upload dist/* # paste a PyPI API token when prompted
45
+ ```
46
+
47
+ ## Before the first publish — checklist
48
+
49
+ - [x] GitHub handle (`HasibDaddy`) filled in across `pyproject.toml`,
50
+ `mkdocs.yml`, `docs/`, and the workflow.
51
+ - [x] `version` matches in `pyproject.toml` and `src/riskkit/__init__.py` (`0.4.0`).
52
+ - [x] `pytest` green (118 tests) and CI passes on GitHub across Python 3.9–3.12.
53
+ - [x] `python -m build` succeeds and `twine check dist/*` passes; the wheel installs
54
+ and imports cleanly in a fresh venv with zero dependencies.
55
+
56
+ ## After publishing
57
+
58
+ - Verify the install: `pip install riskkit-quant` in a clean venv (then `import riskkit`).
59
+ - Update the README install line from the GitHub URL to `pip install riskkit-trading`.
60
+ - Bump the version for the next change (never re-upload the same version).
61
+ - Docs are already live at https://hasibdaddy.github.io/riskkit/ (re-run
62
+ `mkdocs gh-deploy` after docs changes).