Skip to main content

trading-position-risk-mcp

Not financial advice. Use at your own risk. This is a guardrail that enforces rules you configure. It cannot see your broker, does not place orders, and trusts what the agent reports. It can be wrong, and trading can lose money. Test with paper trading first. See Security and trust model.

A deterministic position-sizing and pre-trade risk server for trading agents, served over MCP.

Agents never do sizing math themselves. They ask this server. It applies a rulebook that the human owns, and it answers APPROVED / RESIZED / REJECTED with the rules that fired and an approval token.

The core formula reproduces the E-Mini (ES) Position Sizing Calculator v4.5 spreadsheet exactly (floor(equity × risk% ÷ (stop points × point value))). On top of that it adds costs, micro fallback, portfolio heat, exposure buckets, a daily-loss lockout, drawdown tiers and options.

Quick start

pip install -e ".[dev]"
pytest                                   # 190+ tests, including spreadsheet parity
position-risk-mcp                        # stdio MCP server
position-risk-mcp --http 8765            # streamable HTTP instead (loopback only; see Security)
position-risk-admin size ES long 6500 6498 --no-costs    # same answer as the sheet: 5 contracts

Claude Desktop / Claude Code config:

{
  "mcpServers": {
    "position-risk": {
      "command": "position-risk-mcp",
      "env": {
        "POSITION_RISK_RULES": "/path/to/config/rules.yaml",
        "POSITION_RISK_STATE": "~/.position-risk-mcp/risk_state.json"
      }
    }
  }
}
Env var Default
POSITION_RISK_RULES ./config/rules.yaml, then the repo's config/
POSITION_RISK_INSTRUMENTS ./config/instruments.yaml, then the repo's config/
POSITION_RISK_STATE ~/.position-risk-mcp/risk_state.json

Order flow the agent must follow

check_trade ──► place order (≤ approved_contracts, before expiry) ──► record_fill ──► update_stop* ──► record_close
Tool Purpose
check_trade The gate. Applies every limit; returns verdict, approved_contracts, approval_id, binding limits, and a micro suggestion when the full size rounds to 0.
calculate_position_size Read-only sizing for one trade (ignores other open positions). include_costs=false reproduces the spreadsheet.
record_fill Opens a tracked position against an approval. It refuses quantities above the approval or approvals that have expired. The fill is always recorded (it already happened at the broker), but limits are re-checked and any breaches are returned. If slippage raised the risk, it warns.
cancel_approval Releases the risk reserved by an approval you won't use.
update_stop Moves a stop closer or trails it into profit. Widening is rejected.
record_close Realizes P&L and updates equity, peak, daily P&L, lockouts and drawdown tiers. Supports partial closes.
get_risk_state Equity, drawdown, multiplier, daily budget, positions, bucket exposure, pending approvals, journal.
get_instrument_spec / list_instruments / get_rulebook Reference data.

By design, no tool can change equity, rules or lockouts. Those are owner-only, through the admin CLI:

position-risk-admin show
position-risk-admin set-equity 61250 --note "synced with broker"
position-risk-admin reset-peak --note "reviewed drawdown, resuming"
position-risk-admin unlock-day --note "..."
position-risk-admin remove-position pos_ab12cd34ef --note "closed manually"

What check_trade enforces (config/rules.yaml)

Rule Default Effect
Per-trade risk 1% default, 2% max Larger requests are capped (RESIZED)
Costs commission + 1 tick stop slippage Added to risk per contract
Portfolio heat 5% of equity Total open risk across all positions
Bucket heat 3% of equity ES, MES, NQ, MNQ, RTY, YM, SPX, XSP, SPY and QQQ all count as one us_equity_index exposure
Daily loss 3% of start-of-day equity Hard lockout until the next trading day. A new trade's full stop-out must also fit in what's left of the day's budget
Drawdown tiers −5% from peak → ½ size; −10% → halt Halt lasts until the owner runs reset-peak
Open positions 4
Margin 50% utilization Only for instruments where you set margin_per_contract
Contract cap ES/NQ 20, others 100
Options defined risk only Sized on max loss; naked, short straddle, short strangle and ratio structures are rejected
Stops snapped to tick, away from entry Never widened

Order of evaluation: lockout → drawdown halt → position count → order validity → min(per-trade, heat, bucket, daily budget, margin, cap). The smallest limit wins and is reported in binding_limits.

Examples (with the default $55,000 account)

Trade Result
ES long 6500, stop 6498, costs off 5 contracts (matches the spreadsheet)
ES long 6500, stop 6498, costs on 4 contracts ($116.50 risk each)
ES long 6500, stop 6485 REJECTED → suggestion: 7 MES
SPX credit spread, width 5, credit 1.20 1 spread ($382.60 max loss)
3rd MES position, then an NQ trade NQ REJECTED by bucket_heat → suggests MNQ

Security and trust model

  • Pending approvals reserve risk. Until filled, cancelled or expired, an approval counts against heat, bucket, daily-budget, margin and position-count limits. A new check_trade for a symbol replaces that symbol's earlier pending approval.
  • The agent reports its own fills and closes. The server cannot see your broker. An agent that skips record_close or reports a false exit_price makes equity, lockouts and drawdown tiers wrong. Treat the server as a guardrail for a cooperative agent, not as enforcement, and reconcile with your broker using position-risk-admin set-equity / remove-position.
  • HTTP transport. It binds to loopback by default. Any other --host is refused unless POSITION_RISK_TOKEN (24+ characters) is set; clients then send Authorization: Bearer <token>. There is no TLS: put a reverse proxy in front for anything beyond localhost. Every tool is available to any authenticated client.
  • Rulebook edits. State remembers which rulebook fingerprint created it. If rules.yaml changes, rulebook_changed is true in every response until the owner runs position-risk-admin ack-rulebook.

Design notes

  • Decimal math throughout, so floor() never turns 11.0 into 10.999.
  • Equity is never an input. It starts at account.starting_equity, moves with realized P&L and can be synced with set-equity. A hallucinated account size can't inflate a position.
  • Every response carries the rulebook version and fingerprint, and every state change is journaled, so you can audit which rules approved which trade.
  • The state store is pluggable. JsonFileStore (file lock + atomic write) is the default. For AWS, implement the same transaction() / read() interface on DynamoDB with a conditional version write, and run the server behind Lambda/Fargate with --http.
  • Margins in instruments.yaml are null on purpose. They change, and they differ by broker and session, so set them from your broker.

Roadmap ideas

  • Broker adapters (equity and positions pulled from the broker instead of tracked locally)
  • DynamoDB store + Lambda handler
  • Futures options; per-symbol session calendars for the day rollover
  • Volatility-regime multiplier (e.g. from a VIX regime feed)

License

MIT.

This software enforces rules you configure. It is not financial advice.

Metadata

Release files for trading-position-risk-mcp 0.1.0

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

Source distribution (sdist)

Source distribution for trading-position-risk-mcp 0.1.0
File Size Uploaded
trading_position_risk_mcp-0.1.0.tar.gz 32.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for trading-position-risk-mcp 0.1.0
File Interpreter ABI Platform
trading_position_risk_mcp-0.1.0-py3-none-any.whl Python 3 none any Details

Total release size: 64.3 kB

Release files / trading_position_risk_mcp-0.1.0.tar.gz

Download URL trading_position_risk_mcp-0.1.0.tar.gz
Size 32.6 kB
Tags Source
SHA-256 checksum
How to use checksums
9a59be3d2199e6684e60aa9d2febc78f52cfb7686bb996a89ae392393bd425d9
BLAKE2b-256 checksum
How to use checksums
d792fb9ba2eef0f52bbd1f6c57acbe667f44785b16846606afd35845a808f2c4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release files / trading_position_risk_mcp-0.1.0-py3-none-any.whl

Download URL trading_position_risk_mcp-0.1.0-py3-none-any.whl
Size 31.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
41ac590b9252dce6f52fb02c41141e379eb940ee0ffa5977c881b144248c6450
BLAKE2b-256 checksum
How to use checksums
09e31f87de6ece9f810972017710b317ad11415a54ad960a2babcf002096ee74
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 11, 2026.

Transparency log

Release history Release notifications | RSS feed

0.1.1

2 release files

This release

0.1.0 This release

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