trader-memory-core — Claude Code skill: track investment theses
This skill keeps investment theses from a screener idea through a closed position with a postmortem. Useful when trade decisions get lost between chats.
npx skills add tradermonty/claude-trading-skills --skill trader-memory-core -a claude-codeWhat trader-memory-core does
State persists across conversations: each thesis is its own object with a status history. The lifecycle runs IDEA → ENTRY_READY → ACTIVE → CLOSED. You register theses from screener output through adapters — kanchi-dividend-sop, earnings-trade-analyzer, vcp-screener, pead-screener, canslim-screener, edge-candidate-agent — or manually from a free-form JSON file. The manual source covers fractional-share brokers and hand journaling.
Three scripts do the work: thesis_store.py for transitions and positions, thesis_ingest.py for intake, thesis_review.py for due checks. Run them through the launcher trader_memory_cli.py; it routes through uv run --project <repo> when uv is available, so the pinned jsonschema resolves even from a foreign cwd or from python3 with no global install. You need Python 3.10+, pyyaml and jsonschema. An FMP API key matters only for MAE/MFE calculation in the postmortem.
If the launcher reports that jsonschema is not importable and uv is not on PATH, install uv or add the project dependencies to the current interpreter. Editing state/theses/*.yaml by hand is the wrong fix — schema validation is what keeps thesis state intact. For the kanchi-dividend-sop source, registration is fail-closed: a row without a CLEAN-PASS, PASS-CAUTION or CONDITIONAL-PASS verdict never reaches the store.
What it helps with
- register a screener idea as a tracked thesis
- move a thesis from IDEA to ENTRY_READY and then ACTIVE
- attach position sizing to a thesis
- check which theses are due for review
- close a position and build a postmortem with P&L and MAE/MFE
Example prompts for the agent
- register the thesis from reports/kanchi_entry_signals_2026-03-14.json
- show thesis status for AAPL
- close the position and write a postmortem
How to install trader-memory-core
1Skills CLI (Vercel)
npx skills add tradermonty/claude-trading-skills --skill trader-memory-core -a claude-code2Manually: put the files in place
~/.claude/skills/trader-memory-core/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/trader-memory-core/
1Skills CLI (Vercel)
npx skills add tradermonty/claude-trading-skills --skill trader-memory-core -a codex2Manually: put the files in place
.agents/skills/trader-memory-core/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add tradermonty/claude-trading-skills --skill trader-memory-core -a cursor2Manually: put the files in place
.cursor/skills/trader-memory-core/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install tradermonty/claude-trading-skills trader-memory-core2Manually: put the files in place
.github/skills/trader-memory-core/SKILL.md1Skills CLI (Vercel)
npx skills add tradermonty/claude-trading-skills --skill trader-memory-core -a gemini-cli2Platform CLI
gemini skills install https://github.com/tradermonty/claude-trading-skills --path skills/trader-memory-coreManually: put the files in place
.devin/skills/trader-memory-core/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add tradermonty/claude-trading-skills --skill trader-memory-core -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about trader-memory-core
How do I install trader-memory-core in Claude?
Run npx skills add tradermonty/claude-trading-skills --skill trader-memory-core -a claude-code. The skill lands at ~/.claude/skills/trader-memory-core/SKILL.md.
What does trader-memory-core do?
It tracks investment theses through their lifecycle from idea to closed position, keeps the status history, and generates postmortems with P&L and MAE/MFE analysis.
What do I need to run it?
Python 3.10+, plus the pyyaml and jsonschema packages. An FMP API key is only needed for MAE/MFE calculation in the postmortem.
Source text
SKILL.md · MIT
---
name: trader-memory-core
description: Track investment theses across their lifecycle — from screening idea to closed position with postmortem. Register theses from screener outputs, manage state transitions, attach position sizing, review due dates, and generate postmortem reports with P&L and MAE/MFE analysis. Trigger when user says "register thesis", "track this idea", "thesis status", "review due", "close position", "postmortem", or "trading journal".
---
# Trader Memory Core
## Overview
Persistent state layer that bundles screening → analysis → position sizing → portfolio management outputs into a single "thesis object" per investment idea. Tracks what you thought, what happened, and what you learned — across conversations.
Phase 1 supports single-ticker theses: dividend_income, growth_momentum, mean_reversion, earnings_drift, pivot_breakout.
## When to Use
- After a screener (kanchi, earnings-trade-analyzer, vcp, pead, canslim, edge-candidate-agent) produces candidates
- When transitioning a thesis from IDEA → ENTRY_READY → ACTIVE → CLOSED
- When attaching position-sizer output to a thesis
- When checking which theses are due for review
- When closing a position and generating a postmortem with lessons learned
## Prerequisites
- Python 3.10+
- `pyyaml` (already in project dependencies)
- `jsonschema` (already in `pyproject.toml`; required by `thesis_store.py` and every command that imports it, including `thesis_ingest.py` and `thesis_review.py`)
- FMP API key (optional, only for MAE/MFE calculation in postmortem)
### How to invoke the CLI
Use the stdlib-only launcher `trader_memory_cli.py` for all CLI work. It transparently routes through `uv run --project <repo>` when `uv` is available, so the repo's pinned `jsonschema` is reachable even from a foreign cwd or from `python3` with no global `jsonschema` (e.g. cron / Hermes profile runs):
```bash
# From inside the repo
python3 skills/trader-memory-core/scripts/trader_memory_cli.py store --state-dir state/theses list
# From any other cwd (cron, profile, distribution runner) — point the launcher at the repo
export CLAUDE_TRADING_SKILLS_REPO=/path/to/claude-trading-skills
python3 "$CLAUDE_TRADING_SKILLS_REPO/skills/trader-memory-core/scripts/trader_memory_cli.py" \
store --state-dir /path/to/state/theses list
```
Subcommands: `store` → `thesis_store.py`, `ingest` → `thesis_ingest.py`, `review` → `thesis_review.py`. Everything after the subcommand is forwarded verbatim, so existing argument flags (`--state-dir`, `transition`, `open-position`, etc.) work unchanged.
If the launcher reports that `jsonschema` is not importable AND `uv` is not on `PATH`, the actionable fixes (in priority order) are:
1. Install `uv` (https://docs.astral.sh/uv/) and re-run the launcher.
2. Install the project's dependencies into the current interpreter:
```bash
uv pip install -e /path/to/claude-trading-skills
# or, as a last resort:
python3 -m pip install jsonschema
```
Do **not** treat the thesis store as unavailable and do **not** mutate `state/theses/*.yaml` by hand to work around a missing dependency — schema validation is part of thesis state integrity.
## Workflow
### 1. Register — Ingest screener output as thesis
Read the screener's JSON output and convert to thesis using the appropriate adapter.
```bash
python3 skills/trader-memory-core/scripts/trader_memory_cli.py ingest \
--source kanchi-dividend-sop \
--input reports/kanchi_entry_signals_2026-03-14.json \
--state-dir state/theses/
```
Supported sources: `kanchi-dividend-sop`, `earnings-trade-analyzer`, `vcp-screener`, `pead-screener`, `canslim-screener`, `edge-candidate-agent`, `manual`.
Each thesis starts in `IDEA` status.
For `kanchi-dividend-sop`, registration is fail-closed: each row must carry
one of `CLEAN-PASS`, `PASS-CAUTION`, or `CONDITIONAL-PASS` in `verdict`.
Missing verdicts and `HOLD-REVIEW` / `STEP1-RECHECK` / `FAIL` rows are skipped
and never written to thesis state.
#### Manual brokerage entry (fractional shares)
For trades that did **not** come from a screener — e.g. fractional-share
brokers (IBKR, Robinhood, IBI Smart, Alpaca, eToro) or hand journaling — use
the `manual` source with a free-form JSON file (a single object or an array):
```json
{
"ticker": "AMD",
"thesis_statement": "AMD AI accelerator momentum, fractional IBI Smart position",
"thesis_type": "growth_momentum",
"entry_price": 142.10,
"entry_date": "2026-05-02",
"shares": 7.86,
"stop_price": 128.00
}
```
```bash
python3 skills/trader-memory-core/scripts/trader_memory_cli.py ingest \
--source manual --input amd.json --state-dir state/theses/
```
Required: `ticker`, `thesis_statement`, `thesis_type` (one of
`dividend_income`, `growth_momentum`, `mean_reversion`, `earnings_drift`,
`pivot_breakout`). `stop_price`/`stop_loss` and `target_price`/`take_profit`
map to `exit.stop_loss`/`exit.take_profit`; `entry_price`/`entry_date`/`shares`
are kept in `origin.raw_provenance` — the authoritative entry price/date and
share count are set when you open the position (below). `shares` may be
**fractional** (the schema accepts any positive number). Like every adapter,
manual ingest creates an `IDEA` thesis only — it never mutates status
directly.
To record an **already-open broker position**, run the explicit lifecycle
sequence (the `--event-date` flags backdate the history so it stays
chronological):
```bash
# 1. ingest → IDEA (stamped at entry_date)
python3 .../trader_memory_cli.py ingest --source manual --input amd.json --state-dir state/theses/
# 2. IDEA → ENTRY_READY (backdated)
python3 .../trader_memory_cli.py store --state-dir state/theses/ transition <id> ENTRY_READY \
--reason "existing IBI Smart position" --event-date 2026-05-02
# 3. ENTRY_READY → ACTIVE (fractional shares, backdated)
python3 .../trader_memory_cli.py store --state-dir state/theses/ open-position <id> \
--actual-price 142.10 --actual-date 2026-05-02 --shares 7.86 --event-date 2026-05-02
```
### 2. Query — Search and list theses
```bash
python3 skills/trader-memory-core/scripts/trader_memory_cli.py store \
--state-dir state/theses/ list --ticker AAPL --status ACTIVE
```
Filter by `--ticker`, `--status`, or `--type`.
### 3. Update — Transition, attach position, link reports
Each lifecycle operation is available **both** as a Python function and as a
`thesis_store.py` CLI subcommand. `--event-date` / `--actual-date` accept a
plain `YYYY-MM-DD` (widened to midnight UTC) or a full ISO timestamp.
**State transition** (IDEA → ENTRY_READY only):
```bash
python3 skills/trader-memory-core/scripts/trader_memory_cli.py store --state-dir state/theses/ \
transition <id> ENTRY_READY --reason "validated" [--event-date YYYY-MM-DD]
```
`--event-date` backdates `status_history.at` (use it when backfilling an
existing position so the later backdated `open-position` stays chronological).
Python: `thesis_store.transition(state_dir, thesis_id, "ENTRY_READY", reason, event_date=...)`.
**Open position** (ENTRY_READY → ACTIVE — the only path to ACTIVE):
```bash
python3 .../trader_memory_cli.py store --state-dir state/theses/ open-position <id> \
--actual-price 142.10 --actual-date 2026-05-02 [--shares 7.86] [--event-date 2026-05-02]
```
`--shares` accepts **fractional** quantities. Python:
`thesis_store.open_position(state_dir, thesis_id, actual_price, actual_date, shares=..., event_date=...)`.
`shares` (and `shares_remaining`, when present) must be a **finite, positive
number no greater than 10<sup>12</sup>** (a sanity bound, not an economic
constraint — fractional shares below the cap remain unrestricted). NaN,
±Infinity, and absurdly large values (e.g. a malformed position-sizer
report) are rejected with a clean error at save time, on `open-position`,
`attach-position`, and `trim` alike.
For a **futures** thesis, use `--contracts` instead of `--shares` (see
"Futures positions" below) — if `attach-futures-position` already populated
the position, omit `--contracts` and only pass `--actual-price`/`--actual-date`.
**Trim — partial close** (ACTIVE/PARTIALLY_CLOSED → PARTIALLY_CLOSED, or →
CLOSED when the whole remainder is sold):
```bash
python3 .../trader_memory_cli.py store --state-dir state/theses/ trim <id> \
--shares-sold 4 --price 120.00 --date 2026-05-10
```
`position.shares` is the **original** opened quantity (immutable);
`position.shares_remaining` tracks what is still open. Each trim appends a
`status_history` ledger entry (`shares_sold` / `price` / `proceeds` /
`realized_pnl`). `outcome.pnl_dollars` is the **cumulative** realized P&L
(Σ all trims + final close); `outcome.pnl_pct = pnl_dollars / (entry_price ×
original_shares) × 100`. A trim that sells the entire remainder closes the
thesis (default `exit_reason: manual`, overridable with `--exit-reason`).
`--date` is the ledger timestamp (override with `--event-date`). Python:
`thesis_store.trim(state_dir, thesis_id, shares_sold, price, date, ...)`.
Status invariants: `ACTIVE` ⇒ `shares_remaining == shares`;
`PARTIALLY_CLOSED` ⇒ `0 < shares_remaining < shares`; `CLOSED` ⇒
`shares_remaining == 0`. Legacy theses (no `shares_remaining`) are treated as
fully open at runtime.
For a **futures** thesis, use `--contracts-sold` instead of `--shares-sold` —
`close`/`terminate` need no flag changes; they read `position.asset_type` and
dispatch automatically (see "Futures positions" below).
**Close or invalidate** (→ CLOSED or INVALIDATED):
```bash
python3 .../trader_memory_cli.py store --state-dir state/theses/ close <id> \
--exit-reason target_hit --actual-price 165.00 --actual-date 2026-06-01
python3 .../trader_memory_cli.py store --state-dir state/theses/ terminate <id> \
--terminal-status INVALIDATED --exit-reason "thesis broke"
```
`close` accepts an `ACTIVE` **or** `PARTIALLY_CLOSED` thesis; from
PARTIALLY_CLOSED it adds the final leg and reports the cumulative outcome.
Python: `thesis_store.terminate(state_dir, thesis_id, terminal_status, exit_reason, actual_price, actual_date)`. For CLOSED, delegates to `close()` which computes P&L (fractional-share aware). For INVALIDATED, P&L is computed if entry/exit prices are available.
**Record review** (any non-terminal):
Use `thesis_store.mark_reviewed(state_dir, thesis_id, review_date=..., outcome="OK"|"WARN"|"REVIEW")` to advance next_review_date and record alerts.
**Attach position-sizer output:**
```bash
python3 .../trader_memory_cli.py store --state-dir state/theses/ attach-position <id> \
--report reports/position_report.json
```
Python: `thesis_store.attach_position(state_dir, thesis_id, report_path)` to link position sizing data. Validates that the report mode is "shares" (not budget).
#### Futures positions (contracts / multiplier / direction)
A thesis whose `position.asset_type == "futures"` (or `quantity_unit ==
"contracts"`) is a **futures** thesis. Futures theses use `quantity` /
`quantity_remaining` (whole contracts — no fractional contracts) instead of
`shares` / `shares_remaining`, carry a `direction` (`LONG` or `SHORT`) and a
`multiplier`, and every P&L computation (`close`, `terminate`, `trim`) applies
`(exit_price - entry_price) × multiplier × quantity × sign` (sign = +1
LONG, −1 SHORT) instead of the equity per-unit formula. `close` / `terminate`
/ `trim` / `open-position` all dispatch on `position.asset_type` automatically
— no separate futures subcommands for those four operations. **USD-denominated
contracts only** — there is no FX conversion in the P&L path, so a non-USD
`contract_spec.currency` is rejected outright rather than computing P&L in
the wrong currency's magnitude.
**Attach a futures-position-sizer SIZED report** (step 6 of the Shapiro
contrarian pipeline — futures-position-sizer → trader-memory-core):
```bash
python3 .../trader_memory_cli.py store --state-dir state/theses/ \
attach-futures-position <id> --report reports/futures_position_es_2026-05-10.json
```
Rejects a `NO_TRADE` report (`sizing_status != "SIZED"`), an invalid
`direction`, a non-positive/fractional `contracts` count, a non-finite/non-positive
`contract_spec.multiplier`, or a non-USD `contract_spec.currency`.
Re-attach status guard is `IDEA`/`ENTRY_READY` **only** — stricter than
equity's `attach-position` (which also allows `ACTIVE`): re-attaching a
futures position on `ACTIVE` would silently overwrite the entire position
dict including `direction`, flipping the sign of every subsequent P&L
computation. Correcting an already-open futures position needs a fresh
thesis (or a future dedicated "amend" operation) — not a re-attach.
**Direct open, no attach** (build the position from CLI flags instead of a
SIZED report — `--contract-currency` is **required** here since there is no
`contract_spec` to read a currency from, and must be `USD`):
```bash
python3 .../trader_memory_cli.py store --state-dir state/theses/ open-position <id> \
--actual-price 5000 --actual-date 2026-05-10 \
--contracts 2 --multiplier 50 --direction SHORT --contract-symbol ES \
--contract-currency USD
```
**Trim / close / terminate** — same subcommands as equity, `--contracts-sold`
in place of `--shares-sold`:
```bash
python3 .../trader_memory_cli.py store --state-dir state/theses/ trim <id> \
--contracts-sold 1 --price 4950.00 --date 2026-05-12
python3 .../trader_memory_cli.py store --state-dir state/theses/ close <id> \
--exit-reason target_hit --actual-price 4900.00 --actual-date 2026-05-15
```
Python: `thesis_store.attach_futures_position(state_dir, thesis_id, report_path)`,
`thesis_store.open_position(state_dir, thesis_id, actual_price, actual_date, contracts=..., multiplier=..., direction=...)`.
**Link related reports:**
Use `thesis_store.link_report(state_dir, thesis_id, skill, file, date)` to cross-reference analysis documents.
### 4. Review — Check due dates and monitoring status
```bash
python3 skills/trader-memory-core/scripts/trader_memory_cli.py review \
--state-dir state/theses/ review-due --as-of 2026-04-15
```
List theses with `next_review_date <= as_of`. Use with kanchi-dividend-review-monitor triggers (T1-T5) for systematic review.
### 5. Postmortem — Close and reflect
```bash
python3 skills/trader-memory-core/scripts/trader_memory_cli.py review \
--state-dir state/theses/ postmortem th_aapl_div_20260314_a3f1
```
Generate a structured postmortem in `state/journal/`. If FMP API key is available, includes MAE/MFE (Maximum Adverse/Favorable Excursion) metrics.
**Summary statistics:**
```bash
python3 skills/trader-memory-core/scripts/trader_memory_cli.py review \
--state-dir state/theses/ summary
```
Shows win rate, average P&L%, and per-type breakdown across all closed theses.
## Output Format
### Thesis YAML (state/theses/)
Each thesis is a YAML file with:
- Identity: thesis_id, ticker, created_at
- Classification: thesis_type, setup_type, catalyst
- Lifecycle: status, status_history
- Entry/Exit: target prices, actual prices, conditions
- Position: shares (fractional supported), value, risk (from position-sizer or `open-position --shares`); or, for futures, quantity/multiplier/direction/contract_spec (from futures-position-sizer or `open-position --contracts`)
- Monitoring: review dates, triggers, alerts
- Origin: source skill, screening grade, raw provenance
- Outcome: P&L, holding days, MAE/MFE, lessons learned
### Index (state/theses/_index.json)
Lightweight index for fast queries without loading full YAML files.
### Journal (state/journal/)
Postmortem markdown reports: `pm_{thesis_id}.md`.
## Supported Python Read and Validation API
Use these public functions from `scripts/thesis_store.py` for replay and other
Python consumers:
```python
from pathlib import Path
import thesis_store
thesis = thesis_store.get(Path("state/theses"), thesis_id)
thesis_store.validate_thesis(thesis)
```
- `get(state_dir, thesis_id)` loads fresh YAML data without modifying the thesis
file or index. It does not validate the loaded content. Missing files raise
`FileNotFoundError`; malformed YAML raises `yaml.YAMLError`.
- `validate_thesis(thesis)` checks the JSON Schema and business invariants,
returns `None` on success, and raises `ValueError` on validation failure.
It does not mutate the input or write state.
- Validate loaded or normalized records explicitly before relying on their
schema and business invariants. Keep consumers on these supported functions;
underscore-prefixed helpers are internal implementation details.
## Key Principles
- **Forward-only transitions**: IDEA → ENTRY_READY → ACTIVE → CLOSED (no backtracking)
- **Raw provenance**: All original screener data preserved in `origin.raw_provenance`
- **Atomic writes**: All file operations use tempfile + os.replace
- **Git-tracked state**: `state/` directory is committed, providing audit trail
- **Phase 1 scope**: Single-ticker theses only (pair trades and options in Phase 2)
## Resources
- `references/thesis_lifecycle.md` — Status states and valid transitions
- `references/field_mapping.md` — Source skill → canonical field mapping
- `schemas/thesis.schema.json` — JSON Schema for thesis validation
- `../../examples/workflows/trade-memory-loop/sample-run-full-path/` — Worked end-to-end Plan → Trade → Record → Postmortem → Backtest → Journal example
© tradermonty · MIT · tradermonty/claude-trading-skills