Skip to main content

Nephyr Risk

PyPI version License: MIT

Prediction market risk management for Python bots and AI agents.

Nephyr Risk packages CLM Studios' battle-tested risk math (used in live Polymarket and Kalshi trading bots) as a clean, stateless Python library — with an MCP server so Claude, ChatGPT, and any MCP-compatible agent can call it directly.

Zero dependencies for the core. No database, no API calls, no side effects.


Installation

# Core library only (no external dependencies)
pip install nephyr-risk

# With MCP server support
pip install "nephyr-risk[mcp]"

# With REST API support
pip install "nephyr-risk[api]"

Quick Start

from nephyr_risk import (
    calculate_kelly_size,
    calculate_ev,
    check_risk_status,
    validate_trade,
    get_exposure,
    simulate_drawdown,
)

# 1. Size a position: 60% model probability, 40¢ market price, $1000 bankroll
kelly = calculate_kelly_size(probability=0.60, entry_price=0.40, bankroll=1000)
print(kelly.size)          # ~50.0 (capped at 5% of bankroll)
print(kelly.capped)        # True
print(kelly.full_kelly)      # ~0.3333 (full Kelly)

# 2. Check expected value
ev = calculate_ev(model_probability=0.65, market_price=0.50, platform="polymarket")
print(ev.ev)           # ~0.13 (after fees)
print(ev.edge)         # 0.15 (before fees)
print(ev.is_positive)  # True

# 3. Check current risk status
status = check_risk_status(bankroll=950, daily_pnl=-50, peak_bankroll=1000)
print(status.status)    # 'ACTIVE'
print(status.can_trade) # True

# 4. Pre-trade validation
check = validate_trade(proposed_size=50, bankroll=1000, daily_pnl=0, peak_bankroll=1000)
print(check.approved)                  # True
print(check.projected_daily_loss_pct)  # 5.0

# 5. Portfolio exposure
exposure = get_exposure(
    positions=[{"size": 80}, {"size": 60}, {"size": 40}],
    bankroll=1000
)
print(exposure["total_exposure_pct"])    # 18.0
print(exposure["concentration_risk"])   # False

# 6. Simulate a drawdown scenario
scenario = simulate_drawdown(bankroll=1000, loss_sequence=[30, 40, 50, 60, 80])
print(scenario["max_drawdown_pct"])  # 26.0 → SHUTDOWN triggered
print(scenario["would_shutdown"])    # True
print(scenario["shutdown_after_n"])  # 5

API Reference

calculate_kelly_size(probability, entry_price, bankroll, kelly_fraction=0.25, max_position_pct=5.0, min_size=1.0) → KellyResult

Quarter-Kelly position sizing with a bankroll-percentage hard cap.

Param Type Description
probability float Model probability of YES (0 < p < 1)
entry_price float Market price for YES contract (0 < price < 1)
bankroll float Available capital in USD
kelly_fraction float Fraction of full Kelly (default 0.25)
max_position_pct float Hard cap as % of bankroll (default 5%)
min_size float Minimum position size in USD (default $1)

Returns KellyResult(size, full_kelly, quarter_kelly, capped, cap_reason). Returns size=0 with a descriptive cap_reason for invalid inputs or no edge.


calculate_ev(model_probability, market_price, platform="polymarket") → EVResult

Expected value calculation after platform fees.

Param Type Description
model_probability float Your model's YES probability
market_price float Current YES price on the exchange
platform str "polymarket" or "kalshi"

Returns EVResult(ev, edge, fee_per_leg, round_trip_fee, is_positive).

Fee models:

  • Polymarket: fee = 0.02 × price (flat 2% per leg)
  • Kalshi: fee = 0.07 × P × (1−P) (peaks at P=0.50: 1.75¢/contract)

calculate_fee(price, platform) → float

Fee per leg for a given price and platform. Use calculate_polymarket_fee(price) or calculate_kalshi_fee(price) for direct access.


check_risk_status(bankroll, daily_pnl, peak_bankroll, daily_loss_limit_pct=10.0, drawdown_limit_pct=25.0) → RiskStatus

Current risk status against configured limits.

Returns RiskStatus(status, can_trade, daily_loss_pct, drawdown_pct, warnings).

Status values:

  • "ACTIVE" — All clear, trading allowed
  • "PAUSED" — Daily loss limit hit, resume tomorrow
  • "SHUTDOWN" — Drawdown limit hit, manual review required

Warnings are raised (non-blocking) at 70% of each limit.


validate_trade(proposed_size, bankroll, daily_pnl, peak_bankroll, daily_loss_limit_pct=10.0, drawdown_limit_pct=25.0) → TradeValidation

Pre-trade risk check. Projects worst case (full loss on proposed trade) against limits.

Returns TradeValidation(approved, rejection_reason, projected_daily_loss_pct, projected_drawdown_pct).


get_exposure(positions, bankroll) → dict

Portfolio exposure summary.

positions is a list of dicts, each with at least {"size": float}.

Returns: total_exposure_usd, total_exposure_pct, largest_position_usd, largest_position_pct, num_positions, concentration_risk (bool, triggers at >10% of bankroll in one position), positions_above_5pct.


simulate_drawdown(bankroll, loss_sequence, daily_loss_limit_pct=10.0, drawdown_limit_pct=25.0) → dict

Simulate a hypothetical sequence of losses.

loss_sequence is a list of dollar amounts (positive = loss, negative = gain).

Returns: final_bankroll, max_drawdown_pct, max_daily_loss_pct, total_loss_usd, would_pause, would_shutdown, pause_after_n, shutdown_after_n, events (per-step detail).


MCP Server

Nephyr Risk ships as an MCP server so any MCP-compatible agent (Claude, ChatGPT, etc.) can call these functions as tools.

pip install "nephyr-risk[mcp]"
nephyr-risk-mcp

The server exposes all 7 core functions as MCP tools with full JSON schemas. Add it to your ~/.claude/claude_desktop_config.json:

{
  "mcpServers": {
    "nephyr-risk": {
      "command": "nephyr-risk-mcp"
    }
  }
}

REST API

Nephyr Risk also ships as a FastAPI REST API for use from any language or tool.

Install and run

pip install "nephyr-risk[api]"

# Start the server (reload mode for development)
python -m api

# Or use uvicorn directly
uvicorn api.app:app --host 0.0.0.0 --port 8000 --reload

Interactive Swagger UI is available at http://localhost:8000/docs once the server is running.

Endpoints

Method Path Function
GET /v1/health Health check
POST /v1/kelly calculate_kelly_size
POST /v1/ev calculate_ev
POST /v1/risk-status check_risk_status
POST /v1/validate-trade validate_trade
POST /v1/exposure get_exposure
POST /v1/drawdown simulate_drawdown
POST /v1/fee calculate_fee

curl examples

# Health check
curl http://localhost:8000/v1/health

# Kelly position sizing
curl -s -X POST http://localhost:8000/v1/kelly \
  -H "Content-Type: application/json" \
  -d '{"probability": 0.6, "entry_price": 0.4, "bankroll": 1000}' | python -m json.tool

# Expected value (Kalshi)
curl -s -X POST http://localhost:8000/v1/ev \
  -H "Content-Type: application/json" \
  -d '{"model_probability": 0.65, "market_price": 0.50, "platform": "kalshi"}' | python -m json.tool

# Risk status check
curl -s -X POST http://localhost:8000/v1/risk-status \
  -H "Content-Type: application/json" \
  -d '{"bankroll": 950, "daily_pnl": -50, "peak_bankroll": 1000}' | python -m json.tool

# Pre-trade validation
curl -s -X POST http://localhost:8000/v1/validate-trade \
  -H "Content-Type: application/json" \
  -d '{"proposed_size": 50, "bankroll": 1000, "daily_pnl": 0, "peak_bankroll": 1000}' | python -m json.tool

# Portfolio exposure
curl -s -X POST http://localhost:8000/v1/exposure \
  -H "Content-Type: application/json" \
  -d '{"positions": [{"size": 80}, {"size": 60}, {"size": 40}], "bankroll": 1000}' | python -m json.tool

# Drawdown simulation
curl -s -X POST http://localhost:8000/v1/drawdown \
  -H "Content-Type: application/json" \
  -d '{"bankroll": 1000, "loss_sequence": [30, 40, 50, 60, 70]}' | python -m json.tool

# Fee calculation
curl -s -X POST http://localhost:8000/v1/fee \
  -H "Content-Type: application/json" \
  -d '{"price": 0.5, "platform": "polymarket"}' | python -m json.tool

API key authentication (optional)

Set the NEPHYR_API_KEYS environment variable to a comma-separated list of valid keys. When set, requests with an X-API-Key header are validated against the list. Requests without the header are allowed (free-tier placeholder).

export NEPHYR_API_KEYS="key-abc123,key-def456"
python -m api
curl -H "X-API-Key: key-abc123" -X POST http://localhost:8000/v1/kelly \
  -H "Content-Type: application/json" \
  -d '{"probability": 0.6, "entry_price": 0.4, "bankroll": 1000}'

Pricing

Tier Details
Free 50 calls/month
Paid $29/month — unlimited calls
Agent-to-agent $0.005/call

License

MIT — see LICENSE.

Built by CLM Studios.

Metadata

Release files for nephyr-risk 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for nephyr-risk 0.1.1
File Size Uploaded
nephyr_risk-0.1.1.tar.gz 41.3 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for nephyr-risk 0.1.1
File Interpreter ABI Platform
nephyr_risk-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 71.3 kB

Release files / nephyr_risk-0.1.1.tar.gz

Download URL nephyr_risk-0.1.1.tar.gz
Size 41.3 kB
Tags Source
SHA-256 checksum
How to use checksums
dc74ffb0870d412a98e156ec6ae1f29455ea5dbbadd2e70567ecbdc21cc6d5cb
BLAKE2b-256 checksum
How to use checksums
5f994936416cb6ac661d74f3d097ded6eee31934d5dc51bd4879fbb5df8c53e0
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release files / nephyr_risk-0.1.1-py3-none-any.whl

Download URL nephyr_risk-0.1.1-py3-none-any.whl
Size 30.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
f6fe2105b9d70244b6dd00fbceebb2cf632a5bfac930dee6242934c4a1adc21f
BLAKE2b-256 checksum
How to use checksums
b7cdf5c18eed08e8f6735961798780ae2c6f39000d03674ea88ebd3a8994c31c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.14.3

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page