This guide is for an AI assistant (Claude, ChatGPT or your own agent) connected to a user's Passive Nomads options trade journal through MCP at https://passivenomads.com/mcp. Read it before your first write. The same text is available from the get_guide tool and the journal://guide resource.
a. Purpose and hard limits
- The journal records trades the user has already made at their broker. It never places orders, moves money or connects to a broker by itself.
- Never give financial advice. Describe and summarise; do not recommend trades.
- Before any write, show the user the exact values you will send and wait for an explicit yes. Every write tool echoes the values the journal actually stored (
saved); show those back too. - You cannot delete anything. Deleting a mistaken entry is done by the user on the website.
- Every change you make is logged as
mcp:<your client id>in the user's activity log, and writes are limited to 60 per hour.
b. Data model
- Ticker → combo → legs. A ticker (e.g.
NVDA) holds one or more combos (positions). A combo holds one or more legs. - Every combo needs a name, even a single-leg one (e.g. "Covered call", "Long put hedge"). Send it as
strategy. - Leg types:
instrumentiscall,put(option legs) orstock(an underlying leg: shares of the ticker). - Direction:
sideislongorshort, andqtyis always positive (contracts for options, shares for stock). The website shows long legs as+qtyand short legs as−qty. - Dates are
YYYY-MM-DD. Option legs need astrikeand anexpirydate. The website asks people for days to expiry (DTE) and stores the expiry date; the tools always take the expiry date. - Marks are dated price snapshots per leg (one per leg per day; history is kept). They drive open P&L, Greeks and the performance graph.
c. Units
- Prices are per share. Options are ×100 per contract; the journal does that scaling.
- Greeks are per share, in broker convention, for the option itself:
deltabetween −1 and 1,gamma≥ 0 per $1,thetain $ per day (usually negative),vega≥ 0 in $ per 1 IV point. - Never send position totals. Do not multiply by quantity and do not flip the sign for short legs — the journal applies qty × 100 × long/short.
- IV is a percentage, e.g.
18.5for 18.5%.
d. Opening a trade
Send, for each leg, everything you know about the moment it was opened:
open_price(the contract or share price paid/received),qty,side,strike,expiry;underlying_price(stored as the leg's underlying price at open),iv(IV at entry),delta(stored as delta at open) andgamma,theta,vegaif known;source(e.g."IBKR") andas_of(the snapshot time).
The journal stores these as the leg's opening snapshot, so the user sees Greeks and extrinsic value immediately. Anything you leave out is calculated with Black-Scholes (r = 5%) when an underlying price is known, and shown with a calc tag:
- delta at open ← underlying price at open + IV at entry (or IV implied from the open price);
- current Greeks ← the latest mark's underlying price + IV (mark IV → IV at entry → implied from the mark price);
- extrinsic value ← price − intrinsic value at that snapshot's underlying price.
Without an underlying price nothing can be calculated; the value shows "—".
e. Close vs delete
- Close = the user exited at their broker. Send the close (fill) price with
close_leg(one leg, or part of one) orclose_position(every open leg). The realised P&L counts (see f). - Delete = removing a mistaken entry. It is never done through MCP: ask the user to use Edit → Delete on the website. A deleted entry never counts toward P&L, banked or History.
f. Banked and History
- A leg closed while its combo stays open → its realised P&L is banked on that combo.
- A combo closed entirely while the ticker still has other open combos → its realised P&L stays banked on the ticker's run (not in History yet).
- When the ticker's last open combo closes, the whole run (every combo closed during it, plus everything banked) moves to History, and banked resets. The next trade on that ticker starts a fresh run.
- Punts (short-dated bets such as SPX/ES same-day trades,
is_punt: true) are never banked: they go to History as soon as they close.
g. Rolls
Use roll_position for a roll: it closes the old leg at close_price and opens its replacement (new_strike, new_expiry, new_open_price, optional new_qty) in one call, linked to the old leg, so banked P&L stays on the same combo. Include the new leg's underlying_price, iv and Greeks if known. Do not record a roll as a separate close and add.
h. Syncing from a broker (e.g. IBKR through its own MCP)
- Call
list_positions(open) to get the journal's open legs, with theirleg_ids. - Match broker positions to journal legs by ticker + right (call/put/stock) + strike + expiry + quantity.
- Reconcile:
- a broker position with no journal match →
add_position(new combo, ask the user for its name) oradd_leg(if it belongs to an existing combo); - a journal leg that is gone at the broker with a fill →
close_legat the fill price; - a changed quantity → a partial
close_leg(smaller) oradd_leg(larger); - an expired option →
close_legwithhow: "expired".
- a broker position with no journal match →
update_marksfor every open leg:mark,underlying_price,ivand the four Greeks (per share), withsourceandas_of.update_portfolioonce per day with the account snapshot.- Show the user a summary of every change you intend to make and wait for approval before writing.
Never create duplicates: if a broker position could match more than one journal leg, or the combo grouping is unclear, ask the user.
i. Portfolio snapshots
update_portfolio stores one account snapshot per day (a second call on the same day replaces it):
- required:
source(e.g."IBKR via Claude") andnet_liq(net liquidation value); - optional:
excess_liquidity,maint_margin,init_margin,equity_with_loan,available_funds,buying_power,gross_position,total_cash,leverage,as_of,snap_date(a past day is allowed; a future day is refused); cash_flow= deposits (+) and withdrawals (−) since the previous snapshot. It keeps the time-weighted % return honest: money added is not counted as performance.
Snapshots fill the Portfolio panel and the $ Value and % Return performance charts, which need at least 2 snapshots in the selected range. Without them the user still sees $ P&L (realised P&L from closed trades plus open P&L now). journal_summary returns the latest snapshot.
Backfilling history
When the user first connects, offer to load past account values so the charts have history right away:
- Ask the broker (e.g. the IBKR MCP) for daily net liquidation values over the period the user wants (e.g. since the first journal trade, or the last 12 months), plus deposits and withdrawals by day.
- Show the user the date range, the number of days and the first and last values, and wait for a yes.
- Send them in one call:
update_portfolio { "source": "IBKR via Claude", "snapshots": [ { "snap_date": "2026-04-01", "net_liq": 171250 }, { "snap_date": "2026-04-02", "net_liq": 172010, "cash_flow": 5000 }, … ] }(up to 400 days per call; each call counts as one write toward the 60 per hour). - Put each deposit (+) or withdrawal (−) in that day's
cash_flow, so % Return is not distorted.
Days that already have a snapshot are replaced. Dates must not be in the future, and each day may appear only once per call. Afterwards, keep syncing one snapshot per day.
j. Errors and how to fix them
| Error says | Meaning | Fix |
|---|---|---|
send per-share option Greeks (e.g. delta −1…1), not position totals | A Greek was scaled by quantity or sign-flipped for a short leg | Resend the broker's per-share value for the option itself |
gamma … is negative / vega … is negative | Same mistake on a short leg | Send the unsigned per-share value |
Rate limit reached: at most 60 journal changes per hour | Too many writes this hour; nothing was saved | Wait, batch marks into one update_marks call, or let the user enter it on the website |
No position/leg with id … in your journal | Wrong id (or not this user's) | Call list_positions / get_position and use the returned ids |
This leg is already closed | Closing twice | Refresh with get_position |
Give a close price for every open leg | close_position without every open leg | Include each open leg_id with its close_price |
combo name … is required | strategy missing on add_position | Ask the user what to call the combo |
options need a strike / expiry YYYY-MM-DD | Option leg incomplete | Add the missing field |
stock legs have no option Greeks | Greeks sent for a stock leg | Omit them; stock delta is the share count |
HTTP 401 session has expired | The connection's token expired or was revoked | The user reconnects the connector |
HTTP 403 not a guest session | The user is signed in as a guest | The user creates a free account and reconnects |
k. Worked examples
1. A 3-leg combo: opened, rolled, closed
Open (after the user approves the values):
add_position {
"ticker": "NVDA", "strategy": "Synthetic long + protective put", "opened_on": "2026-10-01",
"legs": [
{ "instrument": "call", "side": "long", "qty": 2, "strike": 175, "expiry": "2026-11-28", "open_price": 14.20,
"underlying_price": 176.10, "iv": 41.2, "delta": 0.58, "gamma": 0.019, "theta": -0.12, "vega": 0.24, "source": "IBKR" },
{ "instrument": "put", "side": "short", "qty": 2, "strike": 175, "expiry": "2026-11-28", "open_price": 11.60,
"underlying_price": 176.10, "iv": 42.0, "delta": -0.44, "source": "IBKR" },
{ "instrument": "put", "side": "long", "qty": 2, "strike": 160, "expiry": "2026-11-28", "open_price": 4.10,
"underlying_price": 176.10, "iv": 46.8, "source": "IBKR" }
]
}
Roll the short put down and out (closes the old leg, opens the new one, banks the difference on the combo):
roll_position { "leg_id": "<short 175 put>", "rolled_on": "2026-10-20", "close_price": 6.40,
"new_strike": 170, "new_expiry": "2026-12-19", "new_open_price": 8.10,
"underlying_price": 184.00, "iv": 39.0, "delta": -0.31, "source": "IBKR" }
Close the whole combo at the broker fills:
close_position { "position_id": "<combo>", "closed_on": "2026-11-14",
"legs": [ { "leg_id": "<long 175 call>", "close_price": 21.30 },
{ "leg_id": "<short 170 put>", "close_price": 1.20 },
{ "leg_id": "<long 160 put>", "close_price": 0.15 } ] }
If NVDA has no other open combo, the whole run (including the roll's banked P&L) moves to History.
2. A full IBKR sync
list_positions {}→ the journal has NVDA 175C ×2 long, NVDA 160P ×2 long, AAPL 245C ×1 short + 100 AAPL shares.- IBKR shows: NVDA 175C ×2, NVDA 160P ×1 (one sold at 2.35 today), AAPL 245C ×1 short, 100 AAPL, and a new MSFT 480C ×1 bought today at 46.50.
- Proposed changes, shown to the user:
close_leg { "leg_id": "<NVDA 160P>", "qty": 1, "close_price": 2.35 }(a partial close: banked on the NVDA combo);add_position { "ticker": "MSFT", "strategy": "<ask the user>", "legs": [ { "instrument": "call", "side": "long", "qty": 1, "strike": 480, "expiry": "2026-12-18", "open_price": 46.50, "underlying_price": 505.00, "iv": 27.4, "delta": 0.68, "source": "IBKR" } ] };- one
update_markscall with every open leg'smark,underlying_price,iv,delta,gamma,theta,vega,source: "IBKR"andas_of; update_portfolio { "source": "IBKR via Claude", "net_liq": 184620, "excess_liquidity": 121350, "maint_margin": 58940, "init_margin": 70490, "equity_with_loan": 180290, "available_funds": 109800, "buying_power": 439200, "gross_position": 262150, "total_cash": 42780, "leverage": 1.42, "cash_flow": 0 }.
- The user says yes → make the calls → show the
savedvalues and a one-line summary.