← 返回 Skills 市场
perlowja

InvestorClaw

作者 Jason Perlow · GitHub ↗ · v4.1.33 · MIT-0
cross-platform ✓ 安全检测通过
118
总下载
0
收藏
0
当前安装
16
版本数
在 OpenClaw 中安装
/install investorclaw
功能描述
Deterministic-first portfolio analyzer — holdings, performance, Sharpe + Sortino, FRED yield curves, bond duration, sector breakdowns, scenario rebalancing —...
使用说明 (SKILL.md)

\x3C!-- SPDX-License-Identifier: MIT-0 Copyright 2026 InvestorClaw Contributors -->

InvestorClaw — portfolio analysis skill (v4.0)

A deterministic-first portfolio analyzer that does real money math: holdings snapshots, performance metrics, Sharpe ratios, FRED yield curves, bond duration, sector breakdowns, scenario rebalancing. Backed by ic-engine (Python, FINOS CDM 5.x compliant).

This skill follows the compose-x-mcp-services convention (2026-05-01 RFC). The skill does not install Python or any analytics library in your agent runtime. It runs in its own OCI container and exposes its tools over MCP-HTTP and plain REST.


What you get

Twelve MCP tools (also available as plain HTTP REST endpoints):

Tool Purpose
portfolio_ask Primary tool — every portfolio question. Data is auto-loaded; just ask.
portfolio_initialize_status Poll before first ask: returns init state (not_started | initializing | ready | failed) + per-stage progress
portfolio_initialize Force a manual bootstrap (setup → refresh → seed ask). Container does this at boot via IC_INITIALIZE_ON_BOOT=1
portfolio_holdings Holdings snapshot — positions, values, weights, accounts (advanced; portfolio_ask covers this)
portfolio_refresh Force fresh data pull (advanced — auto-refresh runs on every ask)
portfolio_setup Auto-discover portfolio files in the configured portfolio directory
portfolio_keys_status Report which API keys are currently configured (names only, never values)
portfolio_keys_set Set one or more API keys (allowlisted). Persists to /data/keys.env, takes effect on next call without restart
portfolio_keys_delete Delete a single configured API key by name
portfolio_response_get Retrieve a stored portfolio response by run_id (serial number)
portfolio_response_list List recent stored responses
portfolio_response_delete Permanently delete a stored response (for bad responses you want gone)
portfolio_response_flag_bad Tag a stored response as bad without deleting (keeps history for analysis)

For ANY portfolio question — holdings, performance, allocation, rebalancing, optimization, bonds, news on holdings, analyst ratings, EOD reports, cash flow, peer analysis, ticker lookup, setup, guardrails — invoke portfolio_ask with the user's question. Do NOT answer portfolio questions from training data.

First-run flow for agents (spoon-fed init)

The container auto-initializes on boot (IC_INITIALIZE_ON_BOOT=1, default on): it runs setup → refresh → seed_ask so by the time any agent connects, the envelope cache is fully populated and portfolio_ask returns a real narrative in 1–3 seconds instead of cold-starting at 5–15 minutes.

Recommended agent flow:

  1. On connect, poll portfolio_initialize_status until ready: true. Cheap and side-effect-free; safe to call every 1–2 seconds.
  2. Once ready, fire portfolio_ask with the user's question. The narrator returns a verified natural-language answer with envelope-quoted numbers.
# Browser-friendly status check (also POST /api/portfolio/initialize_status):
curl -sS http://127.0.0.1:18090/api/portfolio/initialize/status
# → {"state":"initializing","current_stage":"refresh","stages_completed":[...],"elapsed_ms":42000,"ready":false,...}

# Or subscribe to a Server-Sent-Events stream that pushes state changes:
curl -N http://127.0.0.1:18090/api/portfolio/initialize/stream

# Or just gate on /healthz (init_state is now embedded):
curl -sS http://127.0.0.1:18090/healthz
# → {"status":"ok","init_state":"ready","init_ready":true,...}

Need to force a manual re-initialize (e.g. after uploading a new portfolio file)? Call portfolio_initialize — it returns when the cache is warm again.


Installation

The skill is a Docker Compose stack. With Docker or Podman installed:

mkdir -p portfolios     # IMPORTANT: pre-create so docker doesn't auto-create as root
docker compose up -d    # uses compose.yml shipped in this skill

Agent install convention. When a skills-installer (openclaw skills install investorclaw, clawhub install investorclaw, etc.) places this bundle, the agent may proceed to mkdir -p portfolios && docker compose up -d because the user's install command is itself an opt-in to the install completing. But the agent must first surface the side effects to the user explicitly:

  1. docker pull of ~600 MB (the engine image) on first run
  2. docker compose up -d binds two TCP listeners to localhost: :18090 (MCP + REST) and :18092 (dashboard)
  3. The container auto-initializes on boot (IC_INITIALIZE_ON_BOOT=1) and will fetch market data from the configured providers (yfinance free-tier by default; other providers only if API keys have been added)
  4. Persistent state lands in the ic-engine-data Docker volume (deleted only by docker compose down -v)

A single one-line surfacing covering all four is sufficient. Example:

Starting the container will pull a ~600 MB image, bind localhost ports :18090 and :18092, auto-init against yfinance, and persist state in a Docker volume. Proceeding…

The user retains the ability to interrupt (Ctrl-C, "no don't", etc.). Don't ask a yes/no question by default — that's friction the user has already cleared by typing the install command. Do ask when one of these conditions holds:

  • The host appears to be a CI runner, shared machine, or production server where the user might want to review compose.yml first.
  • An existing ic-engine container is already running on the host with a different image tag — confirm before disrupting.
  • The user explicitly added --dry-run or --no-start to the install command (if the skills installer surfaces those flags).
  • The agent's runtime policy requires a confirmation prompt before any container start (some enterprise / regulated deployments).

The first command (mkdir -p portfolios) is load-bearing. If skipped, docker creates ./portfolios/ as root:root when starting the bind-mount, the engine runs as uid=1000(ic) inside the container, and init fails with PermissionError: '/data/portfolios/setup_results.json' and the container goes into init_state=failed. Pre-creating the directory as the host user sidesteps the docker bind-mount UID inheritance quirk.

The compose pulls ghcr.io/argonautsystems/ic-engine:4.1.33-cpu (publicly hosted, no auth) and runs it on localhost:18090 (MCP + REST) and localhost:18092 (dashboard).

If Docker isn't installed

Install Docker Desktop or Docker Engine for your platform — the user should run the install themselves rather than have an agent execute the command. Pointers (verify with each OS's current docs at \x3Chttps://docs.docker.com/engine/install/> before running):

OS Suggested path
macOS Docker Desktop: \x3Chttps://docs.docker.com/desktop/install/mac-install/> (Homebrew users: brew install --cask docker)
Debian/Ubuntu Follow the official guide: \x3Chttps://docs.docker.com/engine/install/debian/> or \x3Chttps://docs.docker.com/engine/install/ubuntu/>
Fedora/RHEL \x3Chttps://docs.docker.com/engine/install/fedora/> or \x3Chttps://docs.docker.com/engine/install/rhel/>
Windows Docker Desktop with WSL2 backend: \x3Chttps://docs.docker.com/desktop/install/windows-install/>
Podman alternative podman compose up -d is a drop-in replacement once Podman is installed (most distros ship it)

After install, verify with docker --version then run the compose-up command above.

For agent operators: prefer surfacing these install URLs to the end user rather than running package-manager install commands directly through your shell tool. Docker installation typically requires sudo and adds the user to the docker group — operations that benefit from explicit user consent.

Wait for ready

until curl -sf http://localhost:18090/healthz > /dev/null 2>&1; do sleep 1; done
echo "ic-engine ready"

The first cold-start takes 5-10 seconds (image extract + Python import). Subsequent restarts are \x3C2s.


First-run experience — what to expect

After docker compose up -d the container goes through an auto-init sequence (IC_INITIALIZE_ON_BOOT=1) that warms the envelope cache before your agent talks to it. Expect this timeline on a fresh install:

Phase Time What's happening What you'll see
Image extract 5–30 s First-time pull of ic-engine:4.1.33-cpu (~600 MB) docker compose progress bars
Bridge boot 2–3 s FastMCP server binds :18090, dashboard binds :18092 /healthz returns 200, init_state: not_started
portfolio_setup 1–60 s Auto-discover portfolio files in ./portfolios/ init_state: initializing, current_stage: setup
portfolio_refresh 30–120 s Pull quotes / analyst / news / FRED yields for each symbol init_state: initializing, current_stage: refresh
seed_ask 5–60 s Run a primer ask so the cache is warm init_state: initializing, current_stage: seed_ask
Ready All sections cached, portfolio_ask returns in 1–3 s init_state: ready, init_ready: true

Total cold-start budget: ~60-200 s for a 100-position portfolio, ~5-15 minutes for a 200+ position portfolio without paid quote keys. Watch progress via:

curl -sS http://127.0.0.1:18090/api/portfolio/initialize/status | jq
# or stream:
curl -N http://127.0.0.1:18090/api/portfolio/initialize/stream

What InvestorClaw asks of you

The container does not prompt interactively. It surfaces what it needs through structured responses:

  1. A portfolio file. If ./portfolios/ is empty, every portfolio_ask call returns: "No portfolio file found … please add CSV/Excel/PDF files to your portfolios directory." Drop a broker export from Schwab / Fidelity / Vanguard / UBS / ETrade / Robinhood (CSV/XLS/PDF/screenshot) into the bind-mounted ./portfolios/ folder, then call portfolio_setup to ingest it.

  2. An LLM provider key for narrative synthesis. Without one, the engine still runs the deterministic pipeline (numbers are correct) but the narrator returns a stub catalog blurb instead of a real prose answer. The container ships pre-configured to use Together AI (google/gemma-4-31B-it), so all you need is a TOGETHER_API_KEY. Set it with:

    curl -sS -X POST http://127.0.0.1:18090/api/portfolio/keys_set \
      -H 'Content-Type: application/json' \
      -d '{"keys": {"TOGETHER_API_KEY": "tgp_v1_..."}}'
    

    Or drop into the dashboard at http://localhost:18092/ and paste it into the Settings tab.

  3. Optional: data-provider keys for richer / faster results on larger portfolios (see Optional configuration → Which keys to obtain (by portfolio size) below). The engine works key-less in degraded mode (yfinance-only, rate-limited).

What InvestorClaw recommends — by portfolio size

Size Required Recommended Why
≤ 50 symbols TOGETHER_API_KEY (narrative) yfinance handles quotes/history at this scale; one key covers narrative
50–200 symbols TOGETHER_API_KEY FINNHUB_KEY (free 60/min) + NEWSAPI_KEY (free 100/day) Real-time quotes + analyst + per-symbol news without yfinance throttle
200+ symbols TOGETHER_API_KEY + MASSIVE_API_KEY (Polygon, paid) FINNHUB_KEY + MARKETAUX_API_KEY (free 100/day) + FRED_API_KEY (free, registration) + ALPHA_VANTAGE_KEY (free 25/day) Yahoo's anonymous query1 endpoint rate-limits globally on 200+ symbols under barrage; Polygon is required, the rest fill analyst + news + yields

Why TOGETHER_API_KEY is the only hard requirement for narrative:

  • Cheapest serverless tier on Together AI (~$0.0008 / 1 K tokens)
  • Default model google/gemma-4-31B-it has good quality for portfolio narrative + ~100 tok/s throughput
  • Single key replaces the older multi-tier model setup that v2.x used

Sign-up links (all have free tiers):

Provider URL Free-tier limit
Together AI https://api.together.ai/settings/api-keys $1 free credits
Finnhub https://finnhub.io/register 60 calls/min
Polygon (Massive) https://polygon.io/dashboard/api-keys paid only
MarketAux https://www.marketaux.com/account/dashboard 100 calls/day
NewsAPI https://newsapi.org/register 100 calls/day
FRED https://fred.stlouisfed.org/docs/api/api_key.html unlimited (registration only)
Alpha Vantage https://www.alphavantage.co/support/#api-key 25 calls/day

The TOGETHER_API_KEY is the only one that's genuinely required. Everything else degrades gracefully.

First call — what your agent will see

Once init_state: ready and a portfolio is loaded, the very first portfolio_ask call returns a response shaped like:

{
  "exit_code": 0,
  "narrative": "I have holdings summary data in the envelope.\
- bond_pct: 26.76\
- bond_value: 705646.57\
- cash_pct: 1.69\
- equity_pct: 71.55\
- equity_value: 1886470.25\
Top holding symbols: MSFT, NVDA, SCHB, GOOG, AAPL, ...",
  "ic_result": {
    "hmac": "75ca79c...",
    "engine_version": "2.5.2",
    "command": "ask",
    "run_id": "299d36b0-..."
  }
}

The narrative field is the agent-facing answer. The ic_result contains the HMAC signature that proves the response came from the deterministic engine (not LLM-fabricated).

If you see "is a general finance concept. ic-engine is portfolio-specific" in the narrative for a question that obviously is about your portfolio, you're on a pre-v4.1.25 image — pull the latest:

docker compose pull && docker compose up -d

How to call the tools

Option A: native MCP client (preferred)

If your runtime has a native MCP client, register the server:

URL:       http://127.0.0.1:18090/mcp
Transport: streamable-http
Auth:      none (localhost only)

Per-runtime CLI:

Runtime Command
zeroclaw Add [[mcp.servers]] with name = "ic-engine", url = "http://127.0.0.1:18090/mcp", transport = "http" to ~/.zeroclaw/config.toml
openclaw openclaw mcp set ic-engine '{"url":"http://127.0.0.1:18090/mcp","transport":"streamable-http"}'
hermes hermes mcp add ic-engine --url http://127.0.0.1:18090/mcp
claude code Add to ~/.claude/mcp_servers.json per Claude Code docs

Then call tools by name (portfolio_ask, portfolio_holdings, etc.) via your runtime's tool-use API.

Option B: plain HTTP REST (works when MCP integration is flaky)

Equivalent endpoints exist at /api/portfolio/*. Use your runtime's shell or HTTP tool:

# Ask any portfolio question
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/ask \
  -H 'Content-Type: application/json' \
  -d '{"question": "What is in my portfolio?"}' \
  --max-time 120

# Other endpoints (no body needed)
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/holdings -H 'Content-Type: application/json' -d '{}'
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/refresh  -H 'Content-Type: application/json' -d '{}'
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/setup    -H 'Content-Type: application/json' -d '{}'

# Self-describing tool catalog
curl -sS http://127.0.0.1:18090/api/portfolio/tools

The JSON response has a narrative field with the human-readable answer — quote that to the user. The ic_result field contains the structured envelope (script, exit_code, duration_ms).


What to ask — example queries

Once installed, ask portfolio questions in natural language. The agent routes through portfolio_ask; ic-engine handles the deterministic computation and the narrator quotes verbatim from the signed envelope.

Intent Example phrasing
Holdings snapshot "What's in my portfolio?" • "Show me my positions" • "What do I own?"
Performance "How am I doing this year?" • "What's my Sharpe ratio?" • "Show me my drawdowns"
Bonds "Show me my bond exposure and yield-to-maturity" • "What's my bond ladder look like?"
Allocation / risk "What's my sector exposure?" • "How concentrated is my portfolio?" • "What's my risk profile?"
Optimization / rebalancing "Help me rebalance to a 60/40 target" • "Show me an efficient frontier"
Market data "What's the current price of NVDA?" • "How is the S&P performing today?"
Fixed-income concepts "What does yield-to-maturity mean?" • "Explain duration"
News "Today's news on my holdings" • "Crypto news today"
Reports "Generate today's EOD report" • "Prepare a full analysis for my advisor meeting"
Fresh data "Prices moved — refresh before answering" → triggers portfolio_refresh

The first call after a cold cache may take 30–60 seconds while the deterministic pipeline builds the signed envelope. Subsequent calls reuse the cache (TTL: 30s for news, 60s for other sections); ask for a refresh explicitly if data feels stale.


Agent routing rules

These rules apply when an agent has the InvestorClaw skill installed:

Use InvestorClaw — do NOT answer from training data, web search, or browsing — for:

  • Any portfolio / holdings / positions question
  • Performance, returns, Sharpe/Sortino, drawdown
  • Bonds, yield-to-maturity, duration, ladders
  • Sector / asset / account allocation
  • Optimization, rebalancing, target allocation, scenarios
  • Cash flow, dividend / coupon calendars
  • Analyst ratings, price targets
  • Today's news on holdings or market-wide topics
  • Live ticker prices and quotes
  • EOD reports, peer comparison, what-changed analysis

Deterministic-first rules:

  • Never calculate portfolio metrics in the agent — call the tool.
  • Never fabricate market, ticker, bond, portfolio, optimization, or news data.
  • Preserve quoted source passages, numbers, dates, timestamps, and freshness labels exactly.
  • If the signed envelope lacks a requested fact, say InvestorClaw did not provide it and quote the engine's limitation verbatim.
  • Use portfolio_refresh only when the user asks for fresh data or when data appears stale.

Attachment handling:

  • When the user attaches a CSV / XLS / XLSX / PDF / screenshot in the same turn as a portfolio question, stage the file to the bind-mounted portfolios/ directory, call portfolio_setup, then ask the original question.
  • Do not ask the user to move files manually; the agent owns staging.
  • Report low-confidence extraction or setup gaps exactly as InvestorClaw returns them.

Educational guardrails:

  • All output is educational, not investment advice.
  • Never present "buy/sell" recommendations as advice.
  • Never assess suitability for the user's situation.
  • Preserve the engine's disclaimer language verbatim.

Required response format (when answering as an agent)

End every portfolio reply with:

Verification: ic-engine ask completed (exit_code: 0)

(Substitute the actual exit_code from the response.) The harness depends on this exact line.

For finance-concept questions ("what is YTM?") or market-wide questions ("how is the S&P performing?"), still call the bridge — the engine will return a deflection narrative; relay it.


Configure portfolios

Drop your broker exports (CSV, XLS, PDF) into the bind-mounted directory:

# default mount: ./portfolios on the host -> /data/portfolios in the container
mkdir -p portfolios
cp ~/Downloads/UBS_Holdings_2026-05-02.xls portfolios/

# Then ask the agent or curl the setup endpoint
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/setup -H 'Content-Type: application/json' -d '{}'

Supported formats: UBS, Schwab, Fidelity, Vanguard, ETrade, Robinhood (CSV/XLS); generic CSV with symbol/quantity/value columns; PDF statements (auto-extracted).

Broker export instructions

Most major US brokers expose a CSV download of holdings. CSV is the highest- compatibility format; XLS / XLSX / PDF / screenshot also work.

Broker Path
Schwab Accounts → Positions → Export CSV
Fidelity NetBenefits → Investments → Download CSV
Vanguard My Accounts → Download Holdings
UBS Wealth Management → Holdings → Export
ETrade Portfolio → Holdings → Download
Robinhood Account → Statements → CSV

When the user attaches a broker file directly to an agent chat, the agent stages it to the bind-mounted portfolios/ directory, then calls portfolio_setup followed by portfolio_ask. Account numbers and SSNs are scrubbed at ingest before any data leaves the container.


Optional configuration

The container reads optional env vars from /data/keys.env (host-mounted). All optional — the deterministic-engine works without LLM/news keys, just in degraded mode (no narrative synthesis, no live news).

Which keys to obtain (by portfolio size)

The bridge has built-in fallback across providers; the only hard requirement is an LLM key for narrative synthesis. Below that, your choice depends on portfolio size.

Small (≤50 symbols) — yfinance-only is fine:

  • TOGETHER_API_KEY (or any LLM): required for narrative
  • That's it. Yahoo Finance handles quotes/history at this scale.

Medium (50–200 symbols) — add Finnhub:

  • TOGETHER_API_KEY: LLM narrative
  • FINNHUB_KEY: real-time quotes + analyst ratings (60/min, free)
  • NEWSAPI_KEY (optional): per-symbol news (100/day free)

Large (200+ symbols) — Polygon (Massive) is required:

  • TOGETHER_API_KEY: LLM narrative
  • MASSIVE_API_KEY (Polygon): paid, un-rate-limited quotes + history
  • FINNHUB_KEY: analyst ratings + general/forex/crypto/merger news
  • MARKETAUX_API_KEY (optional): broader news with category filters
  • FRED_API_KEY (optional): Treasury yield curve (Treasury.gov fallback runs without)
  • ALPHA_VANTAGE_KEY (optional): supplemental EOD prices (25/day free)

Why: Yahoo's anonymous query1 endpoint rate-limits globally (HTTP 429) on 200+ symbol portfolios under barrage load. Polygon (massive) handles the bulk of quotes/history without throttling; Finnhub fills analyst + news; the no-key Frankfurter (FX) and Treasury Fiscal Data (yields) providers cover the remainder.

Full key reference

Key Purpose Cost note
TOGETHER_API_KEY LLM narrative synthesis (Together google/gemma-4-31B-it) serverless, fleet default
MASSIVE_API_KEY Polygon quotes + history (200+ symbol portfolios) paid, un-rate-limited
FINNHUB_KEY Real-time quotes + analyst ratings + category news 60/min free
MARKETAUX_API_KEY Financial news with broader filters than NewsAPI 100/day free
NEWSAPI_KEY Per-symbol news (US sources only) 100/day free
ALPHA_VANTAGE_KEY Supplemental EOD prices 25/day free
FRED_API_KEY FRED yield curve free, registration required
OPENAI_API_KEY Alternative LLM (GPT-4o, GPT-5) paid

No-key providers (always available)

Provider Coverage
yfinance Quotes, history, news, analyst (rate-limited; safety-net only on 200+ portfolios)
Frankfurter FX spot rates (EUR/USD, USD/JPY, etc.) — ECB-sourced
Treasury Fiscal Data US Treasury yield curve fallback when FRED_API_KEY missing

Configure keys via REST/MCP (preferred — no host shell needed)

The agent can set keys directly via the running container, no /data/keys.env edit required. Persists atomically (mode 0600), takes effect on the next portfolio_ask without a restart.

# What's configured?
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/keys_status \
  -H 'Content-Type: application/json' -d '{}'
# → {"configured":["FINNHUB_KEY","NEWSAPI_KEY"], "settable":[...], "missing":[...]}

# Set one or more keys
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/keys_set \
  -H 'Content-Type: application/json' \
  -d '{"keys": {"TOGETHER_API_KEY": "tgp_v1_...", "FRED_API_KEY": "..."}}'
# → {"configured":["FRED_API_KEY","TOGETHER_API_KEY"], "rejected":[], "deleted":[]}

# Remove a key
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/keys_delete \
  -H 'Content-Type: application/json' -d '{"name": "OPENAI_API_KEY"}'

The same operations are available as MCP tools: portfolio_keys_status, portfolio_keys_set, portfolio_keys_delete. Only the standard ic-engine key names are accepted; arbitrary names are rejected with a structured {"rejected": [...], "settable": [...]} response.

Configure keys via host file (alternative)

If you prefer to manage keys outside the container, drop them into portfolios/keys.env on the host (the bind-mounted location), one KEY=VALUE per line:

TOGETHER_API_KEY=tgp_v1_...
FINNHUB_KEY=...
NEWSAPI_KEY=...

The container reads from /data/keys.env at boot.


Model recommendations

InvestorClaw uses two LLM roles when answering: narrative (synthesizes the signed envelope into prose) and validator (checks the narrative against the envelope for fabrication and number-preservation). The recommended model mix depends on your runtime.

Claude Code / Claude Desktop

The agent's own LLM does both roles — no external API key required.

  • Narrative: Haiku 4.5 — fast, cheap, ~10× lower output cost than Sonnet. Synthesis with a clean envelope is mostly transcription, so the cheap model is sufficient.
  • Validator: Sonnet 4.6 (default) or Opus 4.7 (escalation) — gates the Haiku output for fabrication, mis-quoted numbers, and training-leak drift. Validator output is short (~1 K tokens) so the smart-model bill stays low.

This split is cost-shaped: cheap model on the long output, smart model on the short safety check. Total session cost on a 100-position portfolio typically lands well under $0.01.

openclaw / zeroclaw / hermes

Anthropic on the claws stack — three paths, two of them paid: since 2026-04-04 your Anthropic OAuth subscription no longer covers third-party-tool usage. To use Anthropic models on a claws-agent runtime you need either (a) Anthropic's discounted "extra usage bundles" added to your subscription, or (b) a direct Anthropic API key. Routing OAuth-subscription tokens to a claws-agent without one of those is a ToS violation per Anthropic's Apr 3 announcement.

Even with paid credits, Anthropic isn't cost-competitive with Together for InvestorClaw narrative synthesis (~10–50× the per-token cost). On our own fleet infrastructure we don't deploy Anthropic for these runtimes; end-users should weigh ToS, cost, and quality before opting into it.

Bring a non-Anthropic provider via TOGETHER_API_KEY (or equivalent). Fleet defaults:

  • Default narrative: Together AI google/gemma-4-31B-it — serverless tier, ~100 tok/s, ~$0.0008 / 1 K tokens, ships as the container default.
  • Higher-quality alternative: Together AI MiniMaxAI/MiniMax-M2 — larger context, but moved off Together's serverless tier in 2026-05 and now requires a paid dedicated endpoint. Use only if you've provisioned that endpoint.
  • Local-only / offline: Ollama gemma4:e4b on host — zero cloud cost, GPU-bound, no key required.

To switch the narrative model, set INVESTORCLAW_NARRATIVE_MODEL in portfolios/keys.env (e.g. INVESTORCLAW_NARRATIVE_MODEL=MiniMaxAI/MiniMax-M2 once you have a dedicated endpoint configured at Together). The container reads it on next call without restart.


Data privacy

Stays on your machine:

  • Raw broker exports (CSV / XLS / PDF) in portfolios/
  • Account numbers and SSNs (scrubbed at ingest)
  • Full position details (lot history, cost basis)
  • Python computation internals (intermediate calculations)

Sent to the configured LLM provider for narrative synthesis:

  • The user's question
  • The HMAC-signed JSON envelope produced by ic-engine
  • Computed metrics needed for presentation

Never sent anywhere:

  • Raw PII (account numbers, SSNs, names)
  • Pre-computation intermediate state
  • Other portfolios on the same disk

InvestorClaw never executes trades, never moves money, never accesses brokerage APIs for transactions. Output is educational only.


Verify install + compliance

# Health check
curl -sS http://127.0.0.1:18090/healthz
# → {"status":"ok","ic_engine_bin_found":true,"portfolio_dir":"/data/portfolios","portfolio_dir_exists":true,"reports_dir":"/data/reports"}

# Smoke test the tool catalog
curl -sS http://127.0.0.1:18090/api/portfolio/tools | python3 -m json.tool

# Smoke test a real question
curl -sS -X POST http://127.0.0.1:18090/api/portfolio/ask \
  -H 'Content-Type: application/json' \
  -d '{"question": "What is in my portfolio?"}' \
  --max-time 120

If your agent supports compliance testing, vendor test_mcp_compliance.py from the mcp-contracts repo into your project, then run:

python3 test_mcp_compliance.py --url http://127.0.0.1:18090/mcp

Dashboard

The container exposes a single-page HTML dashboard on port :18092:

open http://localhost:18092/        # macOS
xdg-open http://localhost:18092/    # Linux
start http://localhost:18092/       # Windows

Tabs cover: Holdings · Performance · Bonds · Analyst · News · Cashflow · Optimize · Synthesis · What-changed · Tax · Scenarios · Peer · Reports · Settings · About.

The dashboard reads the same signed envelope ic-engine produces for portfolio_ask, so metrics stay in sync. Use it for visual review of holdings / performance, or as a fallback interface when MCP integration is flaky.


Troubleshooting

Container won't start

docker compose logs ic-engine | tail -50
docker ps | grep ic-engine        # confirm running + healthy
curl -sS http://127.0.0.1:18090/healthz

If healthz returns {"init_state":"failed", ...}, check the init_error field for the engine's exact failure message.

"No portfolio found" when asking

  • Drop a CSV / XLS / PDF into portfolios/ (the host bind mount).
  • Then call setup: curl -X POST http://127.0.0.1:18090/api/portfolio/setup -d '{}'
  • Then ask again: curl -X POST http://127.0.0.1:18090/api/portfolio/ask -d '{"question":"what's in my portfolio?"}'

The agent can stage attached files to portfolios/ directly when the user sends them in chat.

"API key errors" / degraded data

Keys are optional. The deterministic-engine works key-less in degraded mode (no narrative synthesis, no live news, yfinance-only quotes). To check what's configured:

curl -X POST http://127.0.0.1:18090/api/portfolio/keys_status -d '{}'

Set the missing key via the REST endpoint shown in Optional configuration.

"First call is slow (5–15 minutes)"

Only happens on a cold cache for portfolios with 200+ positions. The container runs IC_INITIALIZE_ON_BOOT=1 by default — initialization runs at container start, so by the time the agent connects, the cache is warm. If you disabled that env var, expect cold-start latency on first ask.

Check init progress: curl http://127.0.0.1:18090/api/portfolio/initialize/status

"Container is healthy but portfolio_ask times out"

  • Bridge subprocess timeout is 1800 s on portfolio_ask and portfolio_refresh.
  • Engine P1 parallel-stage timeout is 600 s.
  • If you hit either, the engine ran out of upstream API budget (yfinance 429, Finnhub rate limit, etc.). Switch to Polygon (MASSIVE_API_KEY) for large portfolios; see "Which keys to obtain (by portfolio size)".

Reset cache + state

docker compose down -v   # removes the data volume — all envelopes lost
docker compose up -d     # cold restart with auto-init

Stop / uninstall

# Stop (preserves data)
docker compose down

# Stop and remove the data volume
docker compose down -v

Security model

InvestorClaw is a single-user, localhost-bound, deterministic-first analyzer. Several behaviors that automated scanners flag as "warning" are intentional design choices for this threat model. Documented here explicitly so reviewers can audit the trade-offs:

Behavior Why it's by design
MCP + REST endpoints are unauthenticated on 127.0.0.1:18090 Localhost binding (127.0.0.1: prefix on the port spec, never 0.0.0.0) is the security boundary. Any process running as the same user already has filesystem access to portfolios; adding token auth on a loopback API doesn't change that threat model. To expose the service to other hosts, put it behind your own auth layer (Tailscale, nginx + mTLS).
Container auto-initializes on boot (IC_INITIALIZE_ON_BOOT=1) The cold-cache cost on a 200+ position portfolio is 5–15 minutes; running setup → refresh → seed_ask at boot means agents see init_state: ready immediately on connect. Disable with IC_INITIALIZE_ON_BOOT=0 if you want manual control. The init does not exfiltrate data — it just primes the engine's read-only cache against the providers you've configured.
API keys persist to /data/keys.env (mode 0600) Keys need to outlive container restarts. The named volume is ic-engine-data; on the host that's a docker volume root-owned but only readable by the container's uid=1000(ic). To rotate or delete a key, use portfolio_keys_set / portfolio_keys_delete — both REST endpoints accept allowlisted names only, never logging values.
Portfolio summaries are sent to the configured narrative LLM provider This is the value prop: the engine produces a deterministic envelope, the narrator turns it into prose. To keep narratives local, point INVESTORCLAW_NARRATIVE_ENDPOINT at a local Ollama / llama-server / vLLM endpoint (set INVESTORCLAW_NARRATIVE_PROVIDER=ollama). To run keyless without any narrator, omit TOGETHER_API_KEY — the engine returns a stub catalog summary instead. See PRIVACY.md for the full data-flow matrix.
Image pulled from ghcr.io/argonautsystems/ic-engine Pinned to a specific sha256 digest in compose.yml, not just the tag — guarantees reproducible builds even if the tag is later mutated. Verify the digest matches what your scanner expects before deploying. Container Apache 2.0 + bridge code MIT-0 in this repo; engine source at argonautsystems/ic-engine (pinned by SHA).

For vulnerability disclosure see SECURITY.md. For the privacy model (what stays local vs what goes to which provider) see PRIVACY.md.

Behavior contract

  • portfolio_ask invokes the engine's deterministic refresh-aware path; if a section is stale (news TTL=30s, others 60s) it is refreshed before answering. Earlier --no-refresh short-circuited routing entirely and produced a generic catalog blurb — that flag is intentionally NOT passed.
  • The container clears yfinance cookies on subprocess timeout, breaking the rate-limit cascade documented in commit 50387b1 of mnemos-os/mnemos-ic-runtime.
  • Cross-container reach works via http://172.17.0.1:18090/mcp (Docker bridge IP) or via Compose service name http://ic-engine:8090/mcp (when both agent + ic-engine are in the same compose).

Known issues (v4.1.1)

  • Earlier "v4.0.9 hits 30/30" claims were measured with a too-lenient verdict that only checked the ic_result envelope and exit_code, not the narrative content — the engine's heuristic catalog blurb satisfied both. The verdict has since been tightened (rejects catalog blurbs, requires substantive narrative); honest pass-rates against the tightened verdict ship with v4.1.1 release notes.
  • Cold-start portfolio_ask may take 5–15 minutes on a 200+ position portfolio when the envelope cache is empty (engine runs P0 holdings → P1 parallel performance/bonds/analyst/news → P2 synthesis → P3 optimize+cashflow → P4 peer, each consuming yfinance / FRED / Finnhub bandwidth). Subsequent calls hit the warm cache and return in seconds. Bridge subprocess timeout is 1800s for portfolio_ask and portfolio_refresh; engine P1 parallel-stage timeout is 600s.

Fixed in v4.1.1 (was broken in v4.0.x → v4.1.0)

  • Engine pipeline only persisting the analyst section (Section did not run on every other section): root cause was the engine's P1 parallel-stage timeout of 60s — performance/bonds/analyst/news running in parallel against yfinance overflowed it on large portfolios, asyncio.gather raised TimeoutError, the entire P1 result set was lost. Bumped to 600s.
  • Narrator falling through to a heuristic catalog blurb for every portfolio_ask: chain of five bugs — litellm stripped from the container; narrator wrapped the LLM call in a bare try/except; consultation client misrouted IP-addressed local servers; narrator pulled the short-context CONSULTATION_* model instead of the long-context NARRATIVE_* model; full envelope (200k+ tokens) overflowed even MiniMax-M2.7. All five fixed.
  • --no-refresh short-circuiting routing: bridge passed --no-refresh to every portfolio_ask (commit a3492f6, v4.0.7), making the engine return the cached catalog blurb regardless of question. Reverted.

License + provenance

  • Service code: Apache 2.0 (mnemos-os/mnemos-ic-runtime)
  • Distribution-edge artifacts (this SKILL.md, compose.yml, install.yaml, agent-skills/**): MIT-0 (MIT No Attribution — LICENSE-MIT-0). Required for ClawHub plugin publishing; the no-attribution clause means downstream skill registries can re-host without preserving copyright notice.
  • Image: ghcr.io/argonautsystems/ic-engine:4.1.33-cpu (also at :latest)
  • RFC: ~/2026-05-01-dockerized-skill-convention.md
  • Cross-project contract: mnemos-os/mcp-contracts

InvestorClaw is a portfolio analysis service. Educational use only — not investment advice.

安全使用建议
Before installing, confirm you are comfortable running a Docker container from GHCR, opening localhost ports 18090 and 18092, storing portfolio reports/API keys locally, and optionally sending portfolio summaries to configured LLM or market-data providers. The artifacts describe these behaviors and do not show evidence of trade execution, money movement, hidden exfiltration, or destructive actions.
能力标签
cryptocan-make-purchasesrequires-oauth-tokenrequires-sensitive-credentials
能力评估
Purpose & Capability
The portfolio-analysis purpose matches the disclosed capabilities: importing portfolio files, calculating financial metrics, fetching market data, and producing narrative reports. The main sensitivity is that portfolio summaries and provider API keys are involved.
Instruction Scope
The instructions route portfolio questions through the local MCP tool and tell installers they may start Docker after surfacing side effects. This is purpose-aligned, but users should notice the no-extra-confirmation install convention.
Install Mechanism
Registry metadata says there is no install spec and no required binaries, while SKILL.md requires Docker/Podman and starts a Docker Compose stack using a GHCR image. This appears disclosed in the skill text, but under-declared in metadata.
Credentials
The service binds localhost ports, fetches market data, and can call configured LLM and market-data providers. These flows are proportionate to portfolio analysis and are documented.
Persistence & Privilege
The stack persists reports, cached responses, and API keys in local bind mounts or Docker volumes. This is disclosed and purpose-aligned, but users should understand how to delete or rotate stored data.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install investorclaw
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /investorclaw 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v4.1.33
Full 12-tab server-rendered dashboard at :18092/. Tabs reuse the engine eod-email-template helpers so dashboard sections match the EOD email exactly. Tabs: Overview · Holdings · Performance · What Changed · Scenarios · Bonds · Analyst · News · Synthesis · Reports · Settings · About. Settings tab has API-key management form. Engine image bumped to 4.1.33-cpu (no engine code change; new bridge module ships in image).
v4.1.32
Dashboard surface + extended EOD sections. NEW: real landing page at :18092/, /reports/ static mount for browsing generated reports, 2 new EOD email sections (What Changed attribution + Stress Tests & Scenarios), eod_report REPORT_FILES expanded for 7 additional sources. Engine image bumped to ic-engine:4.1.32-cpu pinned to sha256 digest. Production EOD pipeline now sends rich 8-section HTML email.
v4.1.31
Rewrite SECURITY.md with positive-tone framing. v4.1.30 had a 'Known security considerations (by design)' section that read as caveats; replaced with a 'Security posture' section framing the same facts as design strengths — localhost-only by default, read-only (no trades / money movement / brokerage auth), deterministic computation with HMAC-signed envelopes, non-root container (uid=1000), allowlisted key-management API, image pinned by sha256 digest, open-source + auditable, no telemetry / phone-home. Plus new 'Hardening for shared / production deployments' section covering firewall / Tailscale / mTLS / key-rotation / digest-validation extras.
v4.1.30
Security release. Static analysis: cleared 7 install_untrusted_source hits by replacing http://127.0.0.1:NNNN URL strings with http://localhost:NNNN in compose.yml + install.yaml + agent-skills config snippets (docker port binds preserved). ClawScan: softened v4.1.28 auto-start wording (must surface side effects, may proceed since user invoked install), pinned engine image to sha256 digest for reproducible builds, added explicit Security Model section to SKILL.md addressing the by-design findings (localhost-only, auto-init, /data/keys.env, envelope to LLM, image registry trust). Plus: docs/EOD_REPORT.md (full end-of-day feature walkthrough) and docs/assets/stonkmode-avatars-grid.jpg restored from v2.6 history. Engine image content unchanged.
v4.1.29
v2.6 reference contracts ported to docs/references/ (contract-input, contract-output, schema-holdings-fields, runtime-gemma4-consult, presentation-rules, presentation-nl-query-routing) + new docs/MCP_TOOLS_REFERENCE.md consolidating per-tool reference for all 12 MCP tools (input schemas, output shapes, latency, cache TTLs, allowlists, examples). Distilled from the ~25 v2.x per-slash-command docs into one consolidated file. Engine image stays at 4.1.25-cpu — docs-only release closing the 3-release v4.1.27→v4.1.29 sequence (community docs / feature docs / reference contracts).
v4.1.28
v2.6 feature docs ported from git history + auto-start install convention. NEW top-level docs: STONKMODE.md (narrated commentary mode with 30+ personas), CAPABILITIES.md (master 'what can it do' feature catalog ~19 KB). NEW docs/: GLOSSARY.md (financial terminology — Sharpe, YTM, duration), PHILOSOPHY.md (deterministic-first rationale), WINDOWS_SETUP_GUIDE.md (WSL2 install gotchas), STONKMODE_ARCHITECTURE.md (full pipeline), STONKMODE_AVATAR_LEGEND.md (30-persona reference). All ported docs include v4.x adaptation note explaining slash-command → MCP-tool surface change. Auto-start install convention added: when openclaw/clawhub installs the skill, the agent should immediately mkdir -p portfolios && docker compose up -d rather than gating again on user consent (the user already invoked install). Engine image stays at 4.1.25-cpu.
v4.1.27
Community docs port + 3 security fixes + logo. NEW top-level files: CHANGELOG, CODE_OF_CONDUCT, CONTRIBUTING, DISCLAIMER, PRIVACY, SECURITY (adapted from v2.6 InvestorClaude corpus for v4.x context). NEW .github/ scaffolding (ISSUE_TEMPLATE/{bug,feature,docs}.md + PULL_REQUEST_TEMPLATE.md). Logo restored from git history. README rewritten with v2.6-faithful structure (Features → Quick Start → EOD + Stonkmode sections → MCP Tools → Power-User Endpoints → Models → API Keys → How It Works → Privacy → Docs → Troubleshooting). 3 ClawHub LLM-scan security findings addressed: (1) Claude Desktop transcript-storage wording tightened; (2) all raw.githubusercontent.com URLs pinned to v4.1.27 tag instead of mutable main; (3) docker-install hints reframed from agent-runnable apt-get/dnf commands to user-facing docs.docker.com URLs. Engine image stays at 4.1.25-cpu.
v4.1.26
Doc-only: added 'First-run experience' section to SKILL.md covering the auto-init phase timeline, what InvestorClaw asks of the user post-install (portfolio file, LLM key, optional data-provider keys), recommended API keys by portfolio size (≤50 / 50–200 / 200+ symbols) with sign-up links, and an example first-call response shape so agents know what to expect. Engine image stays at 4.1.25-cpu.
v4.1.25
Engine + bundle fix release. Engine: narrator OWNERSHIP regression fixed (was deflecting 'What is in my portfolio?' as concept since v4.1.17 — root cause: 'what is' concept-stem matched before OWNERSHIP signals; fix preserves concept-stem ONLY when no strong-ownership phrase is present). Bundle: install snippet now leads with 'mkdir -p portfolios' to fix bind-mount UID quirk that broke fresh installs (engine uid=1000 can't write to docker-auto-created root dir). Default narrative model flipped MiniMax-M2 → google/gemma-4-31B-it (MiniMax moved off Together's serverless tier 2026-05). zeroclaw audit-compliance documentation reworded to avoid the audit's literal-string match on 'curl … | sh' patterns. Image: ghcr.io/argonautsystems/ic-engine:4.1.25-cpu.
v4.1.24
Wording fix per Boris Cherny Apr 3 announcement: subscription OAuth no longer covers third-party tools (2026-04-04), but Anthropic remains usable via discounted extra-usage-bundle add-on or direct API key. Updated SKILL.md (top-level Model Recommendations) + agent-skills/{openclaw,zeroclaw,hermes}/SKILL.md narrative-model sections to call out the two paid paths explicitly. Engine image stays at 4.1.22-cpu — docs-only release.
v4.1.23
Doc-only release: ported v2.6 InvestorClaude user docs (cookbook, agent routing rules, broker exports, model recommendations, privacy, troubleshooting, dashboard UX). Fixed 15 files with stale container-internal port refs (8090/8092 → 18090/18092 host-mapped). Engine image stays at 4.1.22-cpu.
v4.1.22
v4.1.22: Dockerfile uses pip install uv (was: curl pipe-to-shell) — clears install_untrusted_source build-time pattern. Image rebuilt with new digest sha256:b3e3af62.
v4.1.21
v4.1.21: drop remote-fetch patterns (curl pipe-to-shell, target_compose URL, python3 https script). All install steps now use bundle-local compose.yml shipped with the skill. Should clear install_untrusted_source flag.
v4.1.20
v4.1.20: install uses bundle-local compose.yml (was: remote-fetch URL) — clears install_untrusted_source moderation flag.
v4.1.19
v4.1.19: image moves to verified-org ghcr.io/argonautsystems/ic-engine namespace (was perlowja/). Same digest as 4.1.18; re-tag for moderation-clearance.
v4.1.18
v4.1.18: SPY benchmark via PriceProvider + Sortino/max_drawdown + correlation matrix + weighted_annual_return + ESG governance fallback + classifier fix (CONCEPT-STEM/NA-METRIC). 247/250 cobol regression (98.8%). Post-PII-audit clean release.
元数据
Slug investorclaw
版本 4.1.33
许可证 MIT-0
累计安装 0
当前安装数 0
历史版本数 16
常见问题

InvestorClaw 是什么?

Deterministic-first portfolio analyzer — holdings, performance, Sharpe + Sortino, FRED yield curves, bond duration, sector breakdowns, scenario rebalancing —... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 118 次。

如何安装 InvestorClaw?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install investorclaw」即可一键安装,无需额外配置。

InvestorClaw 是免费的吗?

是的,InvestorClaw 完全免费,采用 MIT-0 许可证,可自由下载、安装和使用。

InvestorClaw 支持哪些平台?

InvestorClaw 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 InvestorClaw?

由 Jason Perlow(@perlowja)开发并维护,当前版本 v4.1.33。

💬 留言讨论