A framework-agnostic risk-management toolkit for systematic traders: position sizing, drawdown laddering, and more.
Project description
riskkit
A framework-agnostic risk-management toolkit for systematic traders.
Most open-source trading tools focus on the fun part — signals, indicators, backtesting engines. They leave the part that actually decides whether you survive thin or absent: how big a position to take, when to cut size, and when to stop trading altogether. That's what blows up retail algo traders, not a bad entry signal.
riskkit is that missing layer. The components are pure Python with no
dependency on any exchange, data provider, or backtesting framework. They
don't know what CCXT is. You feed them numbers; they hand back decisions you can
audit. Drop them into backtesting.py,
vectorbt, backtrader,
freqtrade, or your own loop.
⚠️ Not financial advice.
riskkithelps you implement a risk policy you have chosen. It does not choose one for you, and it cannot make a losing strategy profitable. Test everything on paper first.
Install
pip install riskkit-quant
Zero runtime dependencies. Python 3.9+.
What's in the box
| Component | What it does |
|---|---|
PositionSizer |
Volatility-adjusted fixed-fractional sizing with an optional half-Kelly ceiling, a reduction ladder for losing streaks / drawdowns, and a hard notional cap. |
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. |
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. |
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. |
SessionManager |
Daily trade/loss caps, profit-taking stops, minimum spacing, escalating cooldowns after losing streaks, and tilt detection. |
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. |
Every decision is auditable — the sizer returns which multipliers fired, the stop engine logs each adjustment, and the validator returns a pass/fail line for every single check.
Beyond the six components, riskkit ships a few portfolio-level controls and standalone sizers you can reach for on their own:
- Portfolio caps (enforced by
RiskManageras the book fills): total open notional, total heat (risk-at-stop), and per-sector / asset-class exposure — so no single sector can dominate the book. - Composable sizers (pure functions):
volatility_target_size,inverse_vol_weights(naive risk parity), andkelly_fraction. - Risk metrics: historical
value_at_riskandconditional_value_at_risk.
Quick start
The whole stack, one call
RiskManager is the façade: wire all six components from a single config, push
equity in as your account moves, and ask one question per trade. It keeps the
drawdown, session, and open-position state in sync for you.
from riskkit import RiskManager, RiskConfig, TradeIntent
risk = RiskManager(RiskConfig(
base_risk_pct=1.0, max_notional_pct=4.0,
drawdown=dict(tier1_pct=3, halt_pct=10),
session=dict(max_trades_per_day=5),
correlation=dict(static_groups={"majors": {"BTC/USDT", "ETH/USDT"}}),
))
risk.on_equity(10_000) # refresh drawdown/session state
decision = risk.evaluate(TradeIntent(
symbol="BTC/USDT", side="long",
entry_price=100.0, stop_price=98.0, target_price=104.0,
score=82, atr=2.0, atr_baseline=2.0,
))
if decision.ok:
place(decision.units, decision.stop) # your execution layer
risk.on_fill(decision) # tell riskkit it filled
else:
print("skip:", *decision.reasons, sep="\n ") # every gate that vetoed it
Reach past the façade to any single component when you need to — they're all
exposed (risk.sizer, risk.drawdown, risk.stops, …) and usable standalone.
Don't want to tune every knob? Start from a preset, or load policy from YAML:
risk = RiskManager(RiskConfig.conservative()) # or .balanced() / .aggressive()
cfg = RiskConfig.from_yaml("risk.yaml") # needs riskkit[yaml]
Sizing a trade
from riskkit import PositionSizer, SizingInputs
sizer = PositionSizer(
base_risk_pct=1.0, # risk 1% of equity per trade, before adjustments
max_risk_pct=1.5, # never risk more than 1.5%
max_notional_pct=4.0, # never let a position exceed 4% of equity
)
result = sizer.size(SizingInputs(
equity=10_000,
entry_price=100.0,
stop_price=98.0, # the stop distance defines your risk per unit
atr=2.5, # current volatility
atr_baseline=2.0, # "normal" volatility -> scales risk down when choppy
consecutive_losses=2, # reduction ladder kicks in
drawdown_pct=4.0,
))
if result.units > 0:
print(f"Buy {result.units:.4f} units (risk {result.risk_pct:.2%})")
print("adjustments:", result.multipliers_applied)
else:
print("Skip:", result.reason_for_zero)
Adapting to drawdown
from riskkit import DrawdownManager
dm = DrawdownManager(tier1_pct=3, tier2_pct=5, tier3_pct=7, halt_pct=10)
state = dm.update(current_equity) # call once per equity refresh
if state.halted:
print("No new trades:", state.reason)
else:
size = base_size * state.size_multiplier # scale every position by the tier
The two compose naturally: feed DrawdownManager's drawdown_pct and
size_multiplier straight into the sizer.
Design principles
- Framework-agnostic. No exchange SDK, no pandas requirement in the core, no global state. Just dataclasses in, dataclasses out.
- Auditable, not magic. Every adjustment is named and returned. You can log the exact reason a trade was sized down or skipped.
- Conservative by default. Floors, ceilings, and hard caps bound every knob. The math can recommend; it can never exceed the limits you set.
- Anti-martingale. Size goes down after losses and during drawdowns, never up. There is no "average down" path anywhere in this library.
Integrations
riskkit slots into whatever you already use — the examples are runnable:
- backtesting.py — subclass the
RiskkitStrategyadapter (from riskkit.adapters.backtesting import RiskkitStrategy) and callrisk_long()/risk_short(); every entry is sized and validated by oneRiskConfig, with closed trades fed back to the session manager. Seeexamples/backtesting_riskmanager.py(full façade) orexamples/backtesting_py_strategy.py(justPositionSizer, by hand). - freqtrade —
FreqtradeRiskManager(from riskkit.adapters.freqtrade import FreqtradeRiskManager) drivescustom_stake_amount+confirm_trade_entryfrom oneRiskConfig; seeexamples/freqtrade_callbacks.py. - vectorbt —
size_signals(from riskkit.adapters.vectorbt import size_signals) turns entry signals into a riskkit-sized array forPortfolio.from_signals; seeexamples/vectorbt_sizing.py. - your own loop —
examples/risk_manager.pydrives the fullRiskManagerfaçade end-to-end;examples/multi_asset_book.pyallocates, vol-targets, and vets a cross-sector book through the portfolio caps;examples/pipeline.pyshows the same flow wired by hand.
📖 Full docs: https://hasibvortex369.github.io/riskkit/
Roadmap
riskkit is extracted and generalized from a working risk-first trading bot.
The core six components are in place; next up is making them effortless to drop
into the popular frameworks:
-
PositionSizer,DrawdownManager,StopEngine -
CorrelationGuard,SessionManager,PreTradeValidator - A single
RiskManagerfaçade that wires all six together with one config - Config presets (conservative / balanced / aggressive) + dict/YAML loading
- First-class adapters for backtesting.py, freqtrade, and vectorbt
- A hosted docs site with component recipes
- Portfolio caps (total-exposure, heat, per-sector) + standalone sizers (vol-target, risk-parity, Kelly) + VaR/CVaR
- A PyPI release (
pip install riskkit-quant, thenimport riskkit)
Feedback on the API is genuinely welcome — open an issue. See the full ROADMAP.md, CONTRIBUTING.md, and the examples.
License
MIT © 2026 Hasib. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file riskkit_quant-0.4.1.tar.gz.
File metadata
- Download URL: riskkit_quant-0.4.1.tar.gz
- Upload date:
- Size: 61.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7009123c682ff9bdbd81ea82b8ca275808aa69c1c140341b609509ae511c8b41
|
|
| MD5 |
d49d87024c2eff56a61b0646a407f827
|
|
| BLAKE2b-256 |
372d7f4fff263cc8b8127b0d4cafe608444c118bfe6a99c46e17f2ab0ca73576
|
Provenance
The following attestation bundles were made for riskkit_quant-0.4.1.tar.gz:
Publisher:
release.yml on HasibVortex369/riskkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
riskkit_quant-0.4.1.tar.gz -
Subject digest:
7009123c682ff9bdbd81ea82b8ca275808aa69c1c140341b609509ae511c8b41 - Sigstore transparency entry: 1958940391
- Sigstore integration time:
-
Permalink:
HasibVortex369/riskkit@456a8b7a97f251b62a631c1c85b6a65558e08194 -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/HasibVortex369
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@456a8b7a97f251b62a631c1c85b6a65558e08194 -
Trigger Event:
push
-
Statement type:
File details
Details for the file riskkit_quant-0.4.1-py3-none-any.whl.
File metadata
- Download URL: riskkit_quant-0.4.1-py3-none-any.whl
- Upload date:
- Size: 38.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8234d5c918b8b4330daf43e36babaa8292c88fbe84d4a711c6103cca0edd1b2
|
|
| MD5 |
609eda65a11232c2df5d58279889a4b1
|
|
| BLAKE2b-256 |
03c9269234a03ac5a4ed1566061d3c59e33df90efc6dc99c8c2744ed35c57919
|
Provenance
The following attestation bundles were made for riskkit_quant-0.4.1-py3-none-any.whl:
Publisher:
release.yml on HasibVortex369/riskkit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
riskkit_quant-0.4.1-py3-none-any.whl -
Subject digest:
a8234d5c918b8b4330daf43e36babaa8292c88fbe84d4a711c6103cca0edd1b2 - Sigstore transparency entry: 1958940610
- Sigstore integration time:
-
Permalink:
HasibVortex369/riskkit@456a8b7a97f251b62a631c1c85b6a65558e08194 -
Branch / Tag:
refs/tags/v0.4.1 - Owner: https://github.com/HasibVortex369
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@456a8b7a97f251b62a631c1c85b6a65558e08194 -
Trigger Event:
push
-
Statement type: