English | 中文
Backtrader MCP is an independent, local-first MCP server for building and running reproducible Backtrader strategies. It turns confined CSV files into immutable datasets, typed strategy intent into private drafts, and reviewed drafts into bounded subprocess runs with durable status and reports.
P0 is deliberately offline and backtest-only. It does not expose brokers, stores, credentials, live orders, arbitrary Python execution, or network transports.
Full documentation (English / 中文):
https://cloudquant.github.io/backtrader-mcp/ (also buildable on Read the
Docs; sources under docs/).
- Python 3.10 or newer.
- MCP Python SDK
>=2.0.0,<2.1(validated at2.0.0), usingMCPServerand local stdio. - Independent wheel/source distribution; the only accepted Backtrader runtime is
cloudQuant/backtrader, pinned in package metadata to commit3c967ed61be184c0099ba5bef55d4bed09ad0b4a. - SQLite/WAL state, content-addressed CSV data, private draft files, HMAC capabilities, filesystem locks, idempotency records, and startup recovery.
- Product-owned
prepare_strategy_run,start_strategy_run,get_run_status,cancel_strategy_run, andget_run_resulttools. MCP SDK v2.0.0 does not provide the Tasks extension, so this product does not claim it. - Observability tools:
list_jobs(state-filtered job enumeration),get_run_logs(bounded, path-sanitized job log tails), andlist_target_tree(read-only target preimages for exact change reviews);get_run_statusreportslog_uri,elapsed_seconds, andeta_bound. - All 30 tools carry readOnlyHint/destructiveHint/idempotentHint/openWorldHint
annotations. Tool errors cross the MCP boundary as structured
[code] messagetext with an optionalSuggestion:next step; absolute filesystem paths in error text and job logs are redacted.
The wheel includes seven JSON Schema contracts under
backtrader_mcp/schemas/ and the deterministic comparison policy under
backtrader_mcp/policies/. It also includes its own immutable full metadata
snapshot: 1,155 unique records covering 1,152 functional tests, 1,035
three-file strategy packages, and 1,032 verified mappings. The fourteen
current-fork template entries (seven archetypes by two output profiles) remain
separate from those corpus records.
From this directory, create and activate a dedicated virtual environment, then
install the package. python may be any supported Python 3.10+ interpreter:
python -m venv .runtime
. .runtime/bin/activate
python -m pip install -c constraints/requirements-v2.txt .
python -m backtrader_mcp --helpThe package dependency installs that pinned CloudQuant source. For a source checkout or an environment where the dependency was skipped, run the explicit installer instead:
backtrader-mcp install-backtrader | python -m json.toolIt installs only when Backtrader is absent. If another Backtrader distribution
is already installed, it leaves that distribution untouched and returns the
machine-readable installed_backtrader_untrusted warning.
Register only absolute, trusted roots in the host environment:
BACKTRADER_MCP_STATE_ROOT=/absolute/private/state
BACKTRADER_MCP_SOURCE_ROOTS={"market_data":"/absolute/read-only/csv","functional_corpus":"/absolute/read-only/tests/functional/strategies","package_corpus":"/absolute/read-only/strategies"}
BACKTRADER_MCP_TARGET_ROOTS={"strategies":"/absolute/generated/strategies"}
BACKTRADER_MCP_RUNTIMES={"default":"/absolute/cloudquant-backtrader"}
Root maps are JSON objects. MCP callers receive only root IDs and relative
paths; they cannot submit absolute paths or executable paths. A runtime root
must contain backtrader/__init__.py and have Git origin resolving to
github.com/cloudquant/backtrader; another fork or the public PyPI package is
rejected before a strategy run. If BACKTRADER_MCP_RUNTIMES is omitted, a
verified installed CloudQuant distribution is registered as default.
Before adding a host, export the same values in the installation shell and run the read-only diagnostic. Quoting the JSON values prevents the shell from interpreting them:
export BACKTRADER_MCP_STATE_ROOT='/absolute/private/state'
export BACKTRADER_MCP_SOURCE_ROOTS='{"market_data":"/absolute/read-only/csv"}'
export BACKTRADER_MCP_TARGET_ROOTS='{"strategies":"/absolute/generated/strategies"}'
export BACKTRADER_MCP_RUNTIMES='{"default":"/absolute/cloudquant-backtrader"}'
backtrader-mcp doctor | python -m json.tooldoctor.status must be passed. The report is stable JSON and includes the
installed product and dependency versions, installed-Backtrader provenance,
configured root checks, supported adapters/run profiles, and the actual
Backtrader module_file, version, Git commit, branch, provenance, and runtime
capabilities. An existing non-CloudQuant installed package is reported as a
warning; a configured non-CloudQuant runtime is an error. The CLI diagnostic
itself does not create the state root or write to a source/target root; normal
MCP server startup initializes its private state root before tools are
available.
get_catalog_snapshot returns the slim header by default: counts, hashes,
provenance, and extensions.entry_count, without the 1,155-record entry list.
Set include_entries=true to page through entries with limit (1-100) and
offset; the response reports pagination.total/has_more/truncated.
Every record has source_available=false: search and provenance are
available, but inspect_strategy does not pretend that the original source
bytes were shipped. list_strategy_templates (tool and resource) independently
returns all 14 current-fork archetype/profile templates.
search_strategy_catalog reports total/has_more/offset pagination
metadata and actionable empty-result suggestions.
For an explicit source-attached rebuild, register the functional and package
corpora as two read-only IDs in BACKTRADER_MCP_SOURCE_ROOTS, then call:
{
"tool": "refresh_strategy_catalog",
"arguments": {
"source_root_id": "functional_corpus",
"package_root_id": "package_corpus"
}
}The server scans metadata and hashes only; it never imports, executes, or
modifies a corpus file. The result reports fresh
functional_tests/strategy_packages/mapped counts, a content hash, and a
diagnostic if they differ from the verified 1,152/1,035/1,032 baseline.
Source-attached records use source_available=true; subsequent
inspect_strategy detects changed functional or package bytes. Supplying only
source_root_id preserves the smaller AST-only refresh for a registered
strategy target root.
Replace every /ABSOLUTE/PATH placeholder in the matching file.
Copy examples/hosts/claude-desktop.json into the host's MCP configuration,
or replace every placeholder and run this complete Claude Code command:
claude mcp add-json --scope project backtrader '{
"type": "stdio",
"command": "/ABSOLUTE/PATH/backtrader-mcp/.runtime/bin/backtrader-mcp",
"args": ["serve"],
"env": {
"BACKTRADER_MCP_STATE_ROOT": "/ABSOLUTE/PATH/.backtrader-mcp-state",
"BACKTRADER_MCP_SOURCE_ROOTS": "{\"market_data\":\"/ABSOLUTE/PATH/data\"}",
"BACKTRADER_MCP_TARGET_ROOTS": "{\"strategies\":\"/ABSOLUTE/PATH/generated-strategies\"}",
"BACKTRADER_MCP_RUNTIMES": "{\"default\":\"/ABSOLUTE/PATH/cloudquant-backtrader\"}"
}
}'
claude mcp listRestart Claude Desktop after editing its JSON. Claude Code can verify the
project-scoped server with claude mcp list and its interactive /mcp view.
Merge examples/hosts/codex-config.toml into ~/.codex/config.toml or a
trusted project's .codex/config.toml, then restart the Codex client. The
Codex app, Codex CLI, and Codex IDE extension share this configuration.
Codex's own approval_policy governs the host, but it does not replace either
of this product's trusted local approval records.
The equivalent CLI registration is:
codex mcp add \
--env BACKTRADER_MCP_STATE_ROOT=/ABSOLUTE/PATH/.backtrader-mcp-state \
--env 'BACKTRADER_MCP_SOURCE_ROOTS={"market_data":"/ABSOLUTE/PATH/data"}' \
--env 'BACKTRADER_MCP_TARGET_ROOTS={"strategies":"/ABSOLUTE/PATH/generated-strategies"}' \
--env 'BACKTRADER_MCP_RUNTIMES={"default":"/ABSOLUTE/PATH/cloudquant-backtrader"}' \
backtrader -- /ABSOLUTE/PATH/backtrader-mcp/.runtime/bin/backtrader-mcp serve
codex mcp list --jsonMerge examples/hosts/opencode.json into the global or project OpenCode
configuration. The current configuration places each named local server
directly below mcp; the command is an argument vector and enabled is true.
Run opencode mcp list and require the backtrader server to be connected
before starting a strategy request.
Edit and run examples/hosts/openclaw-add.sh, then keep the successful
openclaw mcp doctor backtrader --probe output as setup evidence.
All four adapters start the same stdio server. A successful connection performs
MCP initialize; the host then discovers tools/list, resources/list, and
prompts/list. Use the host's MCP view/logs to confirm those discovery calls,
then submit this non-mutating first request:
Use only the backtrader MCP server. Call doctor, then call
get_catalog_snapshot. Return doctor.status, the default runtime's module_file,
version and commit, plus snapshot.extensions.entry_count. Do not create a
draft, write a target, or start a run.
Expected evidence is doctor.status=passed, a module_file below the
registered runtime, the expected Backtrader version/commit, and catalog
entry_count=1155. Use these host-specific discovery checks:
| Host | Registration check | Interactive discovery |
|---|---|---|
| Claude Code | claude mcp list |
/mcp shows backtrader, then run the first request |
| Codex | codex mcp list --json |
Start/restart Codex, inspect its MCP tools, then run the first request |
| OpenCode | opencode mcp list |
Require backtrader connected, then run the first request |
| OpenClaw | openclaw mcp doctor backtrader --probe |
Inspect the workspace MCP tools, then run the first request |
For raw protocol evidence independent of host UI wording, the isolated v2
protocol test performs initialize, tools/list, resources/list,
prompts/list, and a typed get_catalog_snapshot call.
Host configuration references: Claude MCP, Codex MCP, OpenCode MCP, and OpenClaw MCP.
For a compatible 0.2.x upgrade, stop every connected host, back up the
private state root, activate the dedicated environment, and reinstall:
. .runtime/bin/activate
python -m pip install --upgrade -c constraints/requirements-v2.txt .
backtrader-mcp doctor | python -m json.toolRestart the host and repeat its registration check and first request. Do not reuse draft validation tokens, change/run tokens, or approvals across an incompatible release. This product does not migrate pre-P0 state.
To uninstall, first remove the backtrader MCP registration from each host
(or delete only its matching configuration entry), stop active runs, then:
. .runtime/bin/activate
python -m pip uninstall backtrader-mcpUninstalling the wheel intentionally leaves the configured state, datasets,
generated strategies, and source files untouched. Archive or remove those
paths separately only after reviewing their contents. If .runtime was
dedicated solely to this product, it can be removed with the platform's file
manager after deactivation.
-
inspect_datasetreads headers and a bounded sample from a configured source root. -
register_datasetrequires an explicit canonical column map and writes a normalized immutable CSV to the CAS. Registration fails if the source changes while read. -
preview_datasetreads a bounded CAS preview. -
derive_tabular_datasetruns onlyidentity,dropna,returns, orsmawith typed parameters and an exact source-manifest hash. It creates a new dataset ID; no DataFrame, callable, pickle, or in-memory object crosses the protocol.returns/smadrop their warmup rows and register the derived column as apandas_custom_linesfeature line, so a derived dataset can feedprecomputed_mlstrategies directly. -
search_strategy_catalogselects one of seven archetypes. -
create_strategy_draftrenders eithersingle_testorpython_bundle. All seven archetypes support both profiles. The spec may declare an allowlisted analyzer set (extensions.analyzers: sqn/calmar/vwr/ timereturn) whose typed metrics flow into the result'sextra_metrics, and an optional canonicalseedthat freezes into the run manifest and seeds the candidate's random/numpy state for reproducible strategies. -
update_strategy_draftrequires the current revision and file hash. -
validate_strategy_draftparses and compiles AST without importing the candidate in the server. It classifies direct Strategy classes separately from cooperative Indicator/LineIterator/Observer/Analyzer objects. A direct Strategy does not have a globalsuper().__init__()requirement; a custom cooperative line object does. -
Read the current target tree with
list_target_tree(relative path to sha256), thenprepare_strategy_changeswith the validation token, exact target preimage hashes, and an idempotency key. It returns a signed change token and a complete create/replace/delete review. -
Review the change, then run the printed command locally:
backtrader-mcp approve \ --change-set CHANGE_ID \ --change-token 'SIGNED_TOKEN' \ --yesThe approval record is created in the private local database. There is no MCP tool for approval and no
approved=trueparameter. -
apply_strategy_changesrequires that approval ID, the signed change token, and a new idempotency key. It rechecks draft and target hashes, stages the complete managed directory, and uses a journaled rename transaction. -
prepare_strategy_runrequires a fresh validation token, immutable dataset ID, registered runtime ID, timeout, one of the fixed run profiles (runonce,runnext,runonce_runnext_compare,fixed_tests, orparameter_sweep), and an idempotency key.parameter_sweepfreezes a typedparam_grid(StrategySpec parameter names to value lists, at most 64 combinations) under the same single approval and ranks the per-combination results byreturn_rate. It freezes the exact draft, artifact, validation, dataset, runtime, profile, and timeout hashes and returns a signed run token. -
Review those frozen inputs, then create a separate execution approval locally:
backtrader-mcp approve \ --run-plan RUN_PLAN_ID \ --run-token 'SIGNED_RUN_TOKEN' \ --yesChange approvals and run approvals have different subject types and cannot be reused for one another.
-
start_strategy_runaccepts only that run plan ID, signed run token, execution approval ID, and a new idempotency key. Pollget_run_statusevery 2-5 seconds until a terminal state (it reportslog_uri,elapsed_seconds, andeta_bound); optionally callcancel_strategy_run; read the normalized JSON and Markdown report withget_run_result. Uselist_jobsto recover job IDs across sessions. On FAILED/TIMED_OUT/ORPHANED, read the bounded sanitized tails withget_run_logsbefore changing the strategy.
Job states are QUEUED, RUNNING, CANCEL_REQUESTED, CANCELLED,
SUCCEEDED, FAILED, TIMED_OUT, and ORPHANED. Every transition is a
compare-and-swap write with one arbitration rule: a terminal state, once
persisted, is never overwritten, and a visible CANCEL_REQUESTED suppresses
SUCCEEDED/FAILED/TIMED_OUT. Cancelling a job that already finished
returns already_terminal instead of touching it.
A server-owned watchdog (started only by serve, never by CLI commands)
consumes the worker heartbeat, enforces the wall-clock deadline with a grace
period, orphans jobs whose worker died, and cleans up detached candidate
process groups. Jobs report a structured error_kind
(user_strategy/resource_limit/timeout/validation/infrastructure/
cancelled/orphaned) so clients can distinguish a strategy bug from a
resource cap or a supervision decision.
The concurrency cap rejects instead of queueing: start_strategy_run fails
with an actionable suggestion when max_concurrent_jobs is reached.
Retention: backtrader-mcp clean --kind jobs|cas|drafts|approvals|nonces --before YYYY-MM-DD removes finished job
records, unreferenced CAS objects, unreferenced drafts, consumed/expired
approvals, and consumed token nonces respectively. Dataset
registration streams row-by-row (bounded memory), deduplicates identical
sources without re-parsing, and catalog refresh reuses an (mtime,size)
fingerprint cache.
Successful results contain exactly eleven canonical metrics:
bar_num, buy_count, sell_count, win_count, loss_count, trade_num,
final_value, sharpe_ratio, annual_return, max_drawdown, and
return_rate. sharpe_ratio and annual_return are nullable. The bundled
comparison-profile-v1 defines deterministic integer equality and floating
point tolerances for run comparison.
- Default sizer is
bt.sizers.FixedSize(stake=1):self.buy()without a size trades exactly one unit. Templates demonstrate explicit sizing where it matters (order_risk uses a risk fraction). - Commission is a fixed percentage applied to both sides
(
cerebro.broker.setcommission(percabs=True)). - There is no cheat-on-close; market orders fill at the next bar's open.
SharpeRatioassumes riskfree rate 0.01 and population standard deviation; the annualization factor follows the data timeframe (252/52/12).max_drawdownis reported as a positive percent.- The yahoo adapter stores raw close prices (
adjclose=False); no adjustment metadata is applied. - The CloudQuant fork resamples with
bar2edge=Trueby default, which differs from upstream backtrader. parameter_sweepruns each grid combination once (runonce) with the params passed throughcerebro.addstrategy(..., **override); one approval covers the whole frozen grid (at most 64 combinations).
register_local_dataset accepts six independent typed adapters:
generic_csv, backtrader_csv, yahoo_csv, mt5_csv, pandas, and
pandas_custom_lines. Every source is parsed and normalized into an immutable
canonical CSV object before execution. The controlled worker then constructs
the named Backtrader adapter for each feed; it does not silently route every
format through GenericCSVData.
Pandas inputs must use source_type=materialized_dataframe and reference a
confined .csv file. Pickles, arbitrary Python objects, and caller-supplied
constructors are rejected. pandas_custom_lines also requires every custom
line to be declared in both lines and columns. MT5 feeds reject
sub-minute timeframes (the adapter would otherwise silently truncate
precision), and alignment.mode accepts only intersection.
Registration enforces a data-quality gate: non-positive OHLC prices and
inconsistent bars (high below low, high below max(open,close), low above
min(open,close)) are rejected with row-numbered errors. Markets where zero or
negative prices are legitimate can opt out per feed with
adapter_options.allow_non_positive_prices=true; OHLC consistency is always
enforced.
Each feed may declare a typed extensions.bar_operation:
{"mode": "direct"}or:
{"mode": "resample", "timeframe": "minutes", "compression": 5}mode may also be replay. Resample and replay are applied with
Cerebro.resampledata and Cerebro.replaydata, respectively. Successful
fixed-test results include per-mode feed_runtime evidence with the requested
format, actual adapter class, bar operation, source row count, and output bar
count.
- Stdio writes protocol frames only to stdout. Candidate stdout/stderr are redirected to per-job private log files.
- Source, target, draft, CAS, and job paths are confined. Symlinks and parent traversal are rejected at caller-controlled boundaries.
- Validation and change tokens use a random 256-bit local secret, random nonces, expirations, and HMAC-SHA256 over canonical hash bindings.
- Apply authorization comes only from the trusted local CLI record.
- Target application replaces the entire managed strategy directory. Callers must provide the exact hash of every pre-existing file, including files that will be deleted.
- Candidate code is never imported by the MCP process. A worker launches it with a fixed interpreter, fixed entrypoint, minimal environment, separate process group, timeout, captured output, and validated result contract.
- Every run manifest fingerprints the runtime's git HEAD commit, the runtime's version-file hash, and the resolved pandas/numpy versions (best-effort: a pip-installed runtime without a git checkout records a null commit).
Process control uses a POSIX session and resource-limit pre-exec hook on
POSIX, while non-POSIX startup omits those options, uses a Windows process
group when available, and preserves only the required SystemRoot launch
variable. The automated suite exercises both branch contracts, but a real
Windows fourteen-cell host run has not yet been recorded.
Static AST policy and a subprocess are not an OS sandbox. Reviewed candidate code still runs with the local user's filesystem permissions. P0 is intended for trusted local strategy development; run it in a container or restricted OS account for hostile code. SQLite state is single-host, and the journaled directory swap is crash-recoverable but not a multi-host distributed transaction. Cancellation is process-based, not an MCP Tasks capability. Watchdog cleanup records PIDs without process start-time binding; on a long-lived host a reused PID could in theory be signalled, and the heartbeat staleness check is the primary defence.
Approval host assumption. Change and run approvals are created only by the
trusted local CLI, but the human-vs-agent separation holds only while the host
does not grant the agent local command execution: an agent with shell access
could run the printed approve command itself. Every approval record and its
audit entry carry the OS identity of the local approver; for stronger
separation, gate the approve CLI behind sudo/another OS account or an
approval daemon outside the agent's reach. Signed tokens now carry one-time
nonces consumed at the authorization landing point (apply/start), and
replayed, expired, or clock-skewed tokens are rejected. On Windows the lock
layer falls back to msvcrt byte-range locking, but a real Windows host run
has still not been recorded.
The CloudQuant Backtrader ecosystem:
cloudQuant/backtrader— the pinned Backtrader runtime fork this product executes (commit3c967ed61be184c0099ba5bef55d4bed09ad0b4a).cloudQuant/backtrader-mcp— this MCP server.cloudQuant/backtrader-skills— companion skills for Backtrader workflows.cloudQuant/backtrader_web— companion web product.cloudQuant/backtrader-agent— companion agent product.cloudQuant/fincore— FinCore, companion financial infrastructure.
Run all commands from this directory:
python -m pip install -e ".[test]"
PYTHONPATH=src python -m pytest -q
ruff check src tests scripts
ruff format --check src tests scripts
PYTHONPATH=src python -m mypy src/backtrader_mcp
# With the four BACKTRADER_MCP_* root variables from the install section:
PYTHONPATH=src python -m backtrader_mcp doctor
PYTHONPATH=src python -m backtrader_mcp audit-independence
python scripts/run_acceptance.py --matrix all \
--require-no-skills --require-no-agentThe project dependency pins cloudQuant/backtrader at commit
3c967ed61be184c0099ba5bef55d4bed09ad0b4a; no public PyPI Backtrader fallback
is accepted. Test runtime resolution is explicit
BACKTRADER_MCP_TEST_RUNTIME_ROOT, then a sibling checkout, then the installed
package. Every candidate is provenance-checked against CloudQuant; an invalid
or untrusted explicit override fails closed. Ruff is the only formatter and
mypy is a required quality gate. The current branch-coverage gate is 80%; its
exact configured value is the release criterion.
Protocol tests install mcp==2.0.0 only into a temporary target directory.
They must not upgrade or remove the user's base-environment mcp==1.20.0.
The fixed acceptance entrypoint consumes a structured 14-cell artifact rather
than inferring success from pytest progress dots. It first builds a temporary
wheel, installs the wheel's [test] dependency closure under the repository
constraints into a clean temporary target, and runs pytest from a separate
directory outside this source checkout. That target must contain the pinned
CloudQuant Backtrader distribution and a matching direct-URL provenance record,
so it does not borrow the active environment's product dependencies.
backtrader_mcp is imported only from the installed wheel target.
The matrix executes all seven archetypes with both output profiles as real
runonce/runnext child-process backtests, covers all six adapters plus
resample/replay, and records inspect/register/preview, draft/validate,
prepare/apply, run, and compare evidence. Its JSON output also records the
wheel SHA-256, installed module origin,
source_checkout_on_sys_path=false, sibling-product absence, and the
independence audit. Callers cannot supply an arbitrary pytest target.
The wheel acceptance additionally verifies the exact full-snapshot SHA-256 and
imports/searches it from a clean temporary site directory outside this
repository, with no sibling AI product on PYTHONPATH.
English | 中文
Backtrader MCP 是一个独立、本地优先的 MCP 服务器,用于构建和运行可复现的 Backtrader 策略。它把受限的 CSV 文件转换为不可变数据集,把 typed 策略意图转换为 私有草稿,把经过审查的草稿转换为带超时边界的子进程运行,并持久化运行状态与报告。
P0 版本刻意设计为离线、仅回测。它不暴露 broker、store、凭证、实盘订单、任意 Python 执行或网络传输。
完整文档(English / 中文):
https://cloudquant.github.io/backtrader-mcp/(亦可在 Read the Docs 构建;
源文件位于 docs/)。
- Python 3.10 及以上。
- MCP Python SDK
>=2.0.0,<2.1(以2.0.0验证),使用MCPServer与本地 stdio。 - 独立的 wheel / 源码分发;唯一可接受的 Backtrader 运行时是
cloudQuant/backtrader,包元数据固定到 commit3c967ed61be184c0099ba5bef55d4bed09ad0b4a。 - SQLite/WAL 状态、内容寻址的 CSV 数据、私有草稿文件、HMAC 能力令牌、文件系统 锁、幂等性记录以及启动恢复。
- 产品自有的
prepare_strategy_run、start_strategy_run、get_run_status、cancel_strategy_run和get_run_result工具。MCP SDK v2.0.0 不提供 Tasks 扩展,因此本产品也不声称支持。 - 可观测性工具:
list_jobs(按状态过滤的作业枚举)、get_run_logs(有界、 绝对路径脱敏的作业日志尾部)与list_target_tree(只读目标树原像,用于 精确变更评审);get_run_status返回log_uri、elapsed_seconds和eta_bound。 - 全部 30 个工具都带有 readOnlyHint/destructiveHint/idempotentHint/
openWorldHint 注解。工具错误以结构化
[code] 消息文本跨越 MCP 边界,可选 附带Suggestion:下一步建议;错误文本与作业日志中的绝对文件系统路径会被脱敏。
wheel 在 backtrader_mcp/schemas/ 下包含七个 JSON Schema 契约,在
backtrader_mcp/policies/ 下包含确定性比较策略。它还内置自己的不可变完整元数据
快照:1,155 条唯一记录,覆盖 1,152 个功能测试、1,035 个三文件策略包和 1,032 个
已验证映射。当前 fork 的十四条模板条目(七个 archetype × 两种输出 profile)与
这些语料记录分开存放。
在本目录下创建并激活一个专用虚拟环境,然后安装本包。python 可以是任意受支持的
Python 3.10+ 解释器:
python -m venv .runtime
. .runtime/bin/activate
python -m pip install -c constraints/requirements-v2.txt .
python -m backtrader_mcp --help包依赖会安装该固定的 CloudQuant 源码。若从源码检出运行或此前跳过了依赖安装,可改用 显式安装入口:
backtrader-mcp install-backtrader | python -m json.tool它只会在 Backtrader 缺失时安装;若已存在其他 Backtrader 发行版,会保持原环境不变并
返回机器可读的 installed_backtrader_untrusted 警告。
只在宿主环境中注册绝对、可信的 root:
BACKTRADER_MCP_STATE_ROOT=/absolute/private/state
BACKTRADER_MCP_SOURCE_ROOTS={"market_data":"/absolute/read-only/csv","functional_corpus":"/absolute/read-only/tests/functional/strategies","package_corpus":"/absolute/read-only/strategies"}
BACKTRADER_MCP_TARGET_ROOTS={"strategies":"/absolute/generated/strategies"}
BACKTRADER_MCP_RUNTIMES={"default":"/absolute/cloudquant-backtrader"}
Root 映射是 JSON 对象。MCP 调用方只能拿到 root ID 和相对路径,不能提交绝对路径或
可执行路径。运行时 root 必须包含 backtrader/__init__.py,且 Git origin 必须解析为
github.com/cloudquant/backtrader;其他 fork 或公开 PyPI 包会在启动策略前被拒绝。若未
设置 BACKTRADER_MCP_RUNTIMES,已验证的已安装 CloudQuant 分发会自动注册为
default。
新增宿主之前,先在安装 shell 中导出同样的值并运行只读诊断。给 JSON 值加引号可以 避免被 shell 解释:
export BACKTRADER_MCP_STATE_ROOT='/absolute/private/state'
export BACKTRADER_MCP_SOURCE_ROOTS='{"market_data":"/absolute/read-only/csv"}'
export BACKTRADER_MCP_TARGET_ROOTS='{"strategies":"/absolute/generated/strategies"}'
export BACKTRADER_MCP_RUNTIMES='{"default":"/absolute/cloudquant-backtrader"}'
backtrader-mcp doctor | python -m json.tooldoctor.status 必须为 passed。报告是稳定的 JSON,包含已安装产品及依赖版本、已安装
Backtrader 的溯源、已配置的 root 检查、支持的 adapter / run profile,以及实际的
Backtrader module_file、版本、Git commit、分支、溯源和运行时能力。已有的非
CloudQuant 已安装包会显示 warning;已配置的非 CloudQuant 运行时则是 error。CLI 诊断
本身不会创建 state root,也不会写入 source / target root;正常 MCP 服务器启动时才会
在工具可用之前初始化自己的私有 state root。
get_catalog_snapshot 默认只返回精简 header:计数、哈希、溯源以及
extensions.entry_count,不含 1,155 条记录列表。设置 include_entries=true 可
以用 limit(1-100)与 offset 分页获取条目;响应会报告
pagination.total/has_more/truncated。全部记录的
source_available=false:搜索和溯源可用,但 inspect_strategy 不会假装原始源
码字节随包分发。list_strategy_templates(工具与资源两种形态)独立返回当前
fork 的全部 14 条 archetype / profile 模板。search_strategy_catalog 返回
total/has_more/offset 分页元数据以及可操作的空结果建议。
若要显式重建带源码的快照,把 functional 和 package 两个语料以两个只读 ID 注册到
BACKTRADER_MCP_SOURCE_ROOTS,然后调用:
{
"tool": "refresh_strategy_catalog",
"arguments": {
"source_root_id": "functional_corpus",
"package_root_id": "package_corpus"
}
}服务器只扫描元数据和哈希,绝不导入、执行或修改任何语料文件。结果会报告最新的
functional_tests/strategy_packages/mapped 计数、内容哈希,以及与已验证的
1,152/1,035/1,032 基线不一致时的诊断信息。带源码的记录使用
source_available=true,后续 inspect_strategy 可检测 functional 或 package 字节
是否变化。只提供 source_root_id 时,则保留针对已注册策略 target root 的更小
AST-only 刷新。
请替换对应文件中每一个 /ABSOLUTE/PATH 占位符。
把 examples/hosts/claude-desktop.json 复制进宿主的 MCP 配置,或替换全部占位符后
运行下面这条完整的 Claude Code 命令:
claude mcp add-json --scope project backtrader '{
"type": "stdio",
"command": "/ABSOLUTE/PATH/backtrader-mcp/.runtime/bin/backtrader-mcp",
"args": ["serve"],
"env": {
"BACKTRADER_MCP_STATE_ROOT": "/ABSOLUTE/PATH/.backtrader-mcp-state",
"BACKTRADER_MCP_SOURCE_ROOTS": "{\"market_data\":\"/ABSOLUTE/PATH/data\"}",
"BACKTRADER_MCP_TARGET_ROOTS": "{\"strategies\":\"/ABSOLUTE/PATH/generated-strategies\"}",
"BACKTRADER_MCP_RUNTIMES": "{\"default\":\"/ABSOLUTE/PATH/cloudquant-backtrader\"}"
}
}'
claude mcp list编辑 Claude Desktop 的 JSON 后需重启。Claude Code 可用 claude mcp list 及其交互
式 /mcp 视图验证项目级服务器。
把 examples/hosts/codex-config.toml 合并到 ~/.codex/config.toml 或可信项目的
.codex/config.toml,然后重启 Codex 客户端。Codex App、Codex CLI 和 Codex IDE
扩展共用这份配置。Codex 自身的 approval_policy 管理宿主,但不替代本产品的任一
可信本地审批记录。
等价的 CLI 注册命令:
codex mcp add \
--env BACKTRADER_MCP_STATE_ROOT=/ABSOLUTE/PATH/.backtrader-mcp-state \
--env 'BACKTRADER_MCP_SOURCE_ROOTS={"market_data":"/ABSOLUTE/PATH/data"}' \
--env 'BACKTRADER_MCP_TARGET_ROOTS={"strategies":"/ABSOLUTE/PATH/generated-strategies"}' \
--env 'BACKTRADER_MCP_RUNTIMES={"default":"/ABSOLUTE/PATH/cloudquant-backtrader"}' \
backtrader -- /ABSOLUTE/PATH/backtrader-mcp/.runtime/bin/backtrader-mcp serve
codex mcp list --json把 examples/hosts/opencode.json 合并到全局或项目级 OpenCode 配置。当前配置把每个
具名的本地服务器直接放在 mcp 下;command 是参数向量,enabled 为 true。运行
opencode mcp list,并要求 backtrader 服务器在发起策略请求前已连接。
编辑并运行 examples/hosts/openclaw-add.sh,然后保留成功的
openclaw mcp doctor backtrader --probe 输出作为安装证据。
四个 adapter 启动的是同一个 stdio 服务器。连接成功会执行 MCP initialize,随后
宿主发现 tools/list、resources/list 和 prompts/list。用宿主的 MCP 视图 / 日
志确认这些发现调用,然后提交下面这个非变更的首个请求:
Use only the backtrader MCP server. Call doctor, then call
get_catalog_snapshot. Return doctor.status, the default runtime's module_file,
version and commit, plus snapshot.extensions.entry_count. Do not create a
draft, write a target, or start a run.
预期证据是 doctor.status=passed、位于已注册运行时之下的 module_file、预期的
Backtrader 版本 / commit,以及 catalog entry_count=1155。各宿主的发现检查如下:
| 宿主 | 注册检查 | 交互式发现 |
|---|---|---|
| Claude Code | claude mcp list |
/mcp 显示 backtrader,然后运行首个请求 |
| Codex | codex mcp list --json |
启动 / 重启 Codex,查看其 MCP 工具,然后运行首个请求 |
| OpenCode | opencode mcp list |
要求 backtrader 已连接,然后运行首个请求 |
| OpenClaw | openclaw mcp doctor backtrader --probe |
查看工作区 MCP 工具,然后运行首个请求 |
如需独立于宿主 UI 措辞的原始协议证据,隔离的 v2 协议测试会执行 initialize、
tools/list、resources/list、prompts/list 和一次 typed
get_catalog_snapshot 调用。
宿主配置参考: Claude MCP、 Codex MCP、 OpenCode MCP 和 OpenClaw MCP。
兼容的 0.2.x 升级:停止所有已连接宿主、备份私有 state root、激活专用环境并重装:
. .runtime/bin/activate
python -m pip install --upgrade -c constraints/requirements-v2.txt .
backtrader-mcp doctor | python -m json.tool重启宿主并重复其注册检查和首个请求。不要跨不兼容版本复用草稿校验令牌、change/run 令牌或审批。本产品不迁移 pre-P0 state。
卸载时,先从每个宿主移除 backtrader MCP 注册(或只删除其对应配置项),停止活动
运行,然后:
. .runtime/bin/activate
python -m pip uninstall backtrader-mcp卸载 wheel 时有意保留已配置的 state、数据集、生成的策略和源文件不动。请在审查内容
后再单独归档或删除这些路径。若 .runtime 仅专用于本产品,可在 deactivate 后用平
台文件管理器删除。
-
inspect_dataset从已配置的 source root 读取表头和有界样本。 -
register_dataset需要显式的规范列映射,并把归一化的不可变 CSV 写入 CAS。读取 期间源文件发生变化则注册失败。 -
preview_dataset读取有界的 CAS 预览。 -
derive_tabular_dataset只运行identity、dropna、returns或sma,带 typed 参数和精确的 source-manifest 哈希。它创建新的 dataset ID;任何 DataFrame、callable、pickle 或内存对象都不会穿越协议。 -
search_strategy_catalog在七个 archetype 中选择一个。 -
create_strategy_draft渲染single_test或python_bundle。七个 archetype 都支持这两种 profile。 -
update_strategy_draft需要当前 revision 和文件哈希。 -
validate_strategy_draft解析并编译 AST,但不在服务器中导入候选项。它把直接 Strategy 类与协作式 Indicator/LineIterator/Observer/Analyzer 对象分开判定。 直接 Strategy 没有全局super().__init__()要求;自定义协作式 line 对象则需要。 -
prepare_strategy_changes需要校验令牌、精确的 target 原像哈希和一个幂等键。它 返回一个签名 change token 和完整的 create/replace/delete 审查。 -
审查 change 后,在本地运行打印出的命令:
backtrader-mcp approve \ --change-set CHANGE_ID \ --change-token 'SIGNED_TOKEN' \ --yes审批记录写入私有本地数据库。没有用于审批的 MCP 工具,也没有
approved=true参数。 -
apply_strategy_changes需要该审批 ID、签名 change token 和一个新的幂等键。它 会重新检查草稿和 target 哈希,暂存完整的受管目录,并使用带日志的 rename 事务。 -
prepare_strategy_run需要一个新的校验令牌、不可变 dataset ID、已注册的运行时 ID、超时、固定 run profile 之一(runonce、runnext、runonce_runnext_compare或fixed_tests)以及一个幂等键。它冻结确切的草稿、 artifact、校验、数据集、运行时、profile 和超时哈希,并返回签名 run token。 -
审查这些冻结输入后,在本地单独创建一个执行审批:
backtrader-mcp approve \ --run-plan RUN_PLAN_ID \ --run-token 'SIGNED_RUN_TOKEN' \ --yeschange 审批和 run 审批的 subject type 不同,不能互相复用。
-
start_strategy_run只接受该 run plan ID、签名 run token、执行审批 ID 和一个新 的幂等键。每 2-5 秒轮询一次get_run_status直到终态(响应含log_uri、elapsed_seconds与eta_bound);可选调用cancel_strategy_run;用get_run_result读取归一化的 JSON 和 Markdown 报告。跨会话找回 job ID 用list_jobs。FAILED/TIMED_OUT/ORPHANED 时,先用get_run_logs读取有界脱敏 日志尾部,再修改策略。
作业状态为 QUEUED、RUNNING、CANCEL_REQUESTED、CANCELLED、SUCCEEDED、
FAILED、TIMED_OUT 和 ORPHANED。每个迁移都是 compare-and-swap 写入,仲裁
规则唯一:终态一旦持久化永不被覆写,可见的 CANCEL_REQUESTED 会抑制
SUCCEEDED/FAILED/TIMED_OUT。取消已结束的作业会返回 already_terminal
而不是触碰它。
服务器自有的 watchdog(仅由 serve 启动,CLI 命令从不启动)消费 worker
心跳、以宽限期强制执行墙钟截止、把 worker 已死亡的作业判定为孤儿,并清理
脱离的候选进程组。作业报告结构化的 error_kind
(user_strategy/resource_limit/timeout/validation/infrastructure/
cancelled/orphaned),让客户端能区分策略 bug、资源封顶与监督决策。
并发上限是"拒绝而非排队":达到 max_concurrent_jobs 时
start_strategy_run 失败并附可操作建议。保留策略:backtrader-mcp clean --kind jobs|cas|drafts|approvals|nonces --before YYYY-MM-DD 分别删除已结束的
作业记录、未被引用的 CAS 对象、未被引用的草稿、已消费或已过期的审批、已消费
的令牌 nonce。数据集注册逐行
流式处理(有界内存)、相同源免重解析去重,目录刷新复用 (mtime,size) 指纹缓存。
成功结果恰好包含 11 个规范指标:bar_num、buy_count、sell_count、
win_count、loss_count、trade_num、final_value、sharpe_ratio、
annual_return、max_drawdown 和 return_rate。sharpe_ratio 和
annual_return 可为空。内置的 comparison-profile-v1 定义了运行比较时确定性的整
数相等判定和浮点容差。
- 默认 sizer 为
bt.sizers.FixedSize(stake=1):不带 size 的self.buy()恰好 成交 1 单位。模板在关键处演示显式 sizing(order_risk 使用风险比例)。 - 佣金为双边固定百分比(
cerebro.broker.setcommission(percabs=True))。 - 无 cheat-on-close;市价单在下一根 bar 的开盘价成交。
SharpeRatio假设无风险利率 0.01、总体标准差;年化因子随数据 timeframe (252/52/12)。max_drawdown以正数百分比报告。- yahoo adapter 存储未调整收盘价(
adjclose=False),不应用调整元数据。 - CloudQuant fork 默认
bar2edge=True重采样,与上游 backtrader 不同。 parameter_sweep每个网格组合以 runonce 执行一次,参数经cerebro.addstrategy(..., **override)传入;一次审批覆盖整个冻结网格 (最多 64 个组合)。
register_local_dataset 接受六个独立的 typed adapter:generic_csv、
backtrader_csv、yahoo_csv、mt5_csv、pandas 和 pandas_custom_lines。每个
源在执行前都被解析并归一化为不可变的规范 CSV 对象。受控 worker 随后为每个 feed 构
造具名的 Backtrader adapter,而不会把所有格式都悄悄走 GenericCSVData。
Pandas 输入必须使用 source_type=materialized_dataframe 并引用一个受限的 .csv
文件。pickle、任意 Python 对象和调用方提供的构造器都会被拒绝。pandas_custom_lines
还要求每条自定义 line 同时在 lines 和 columns 中声明。
每个 feed 可声明一个 typed extensions.bar_operation:
{"mode": "direct"}或:
{"mode": "resample", "timeframe": "minutes", "compression": 5}mode 也可为 replay。resample 和 replay 分别通过 Cerebro.resampledata 和
Cerebro.replaydata 应用。成功的 fixed-test 结果包含按 mode 记录的
feed_runtime 证据:请求格式、实际 adapter 类、bar 操作、源行数和输出 bar 数。
- stdio 只把协议帧写入 stdout。候选项的 stdout/stderr 被重定向到按作业私有的日志 文件。
- source、target、draft、CAS 和作业路径都被限定。符号链接和父目录穿越在调用方控制 的边界处被拒绝。
- 校验和 change token 使用随机 256 位本地密钥、随机 nonce、过期时间,以及对规范哈 希绑定的 HMAC-SHA256。
- apply 授权只来自可信的本地 CLI 记录。
- target 应用会替换整个受管策略目录。调用方必须提供每个既有文件的精确哈希,包括即 将被删除的文件。
- 候选代码绝不被 MCP 进程导入。worker 用固定解释器、固定入口、最小环境、独立进程 组、超时、捕获输出和已校验的结果契约来启动它。
进程控制在 POSIX 上使用独立 session 与 resource-limit pre-exec hook;在非 POSIX 上
不会传入这两个参数、可用时使用 Windows process group,并只保留启动所需的
SystemRoot 环境变量。自动化套件覆盖两类分支契约,但尚未记录真实 Windows 的十四格
host 运行结果。
静态 AST 策略加子进程并不是 OS 沙箱。经审查的候选代码仍以本地用户的文件系统权限运 行。P0 面向可信的本地策略开发;对恶意代码请在容器或受限 OS 账户中运行。SQLite 状态 是单主机的,带日志的目录交换可崩溃恢复,但不是多主机分布式事务。取消是基于进程的, 不是 MCP Tasks 能力。watchdog 清理只记录 PID 而不绑定进程启动时间;在长期运行的宿主 上,被复用的 PID 理论上可能被误发信号,心跳失速判定是主要防线。
审批的宿主假设。 change/run 审批只由可信本地 CLI 创建,但"人机分离"
只在宿主不给 Agent 本地命令执行能力时成立:有 shell 权限的 Agent 可以自行
运行打印出来的 approve 命令。每条审批记录及其审计行都携带本地审批者的 OS
身份;需要更强隔离时,请把 approve CLI 置于 sudo/另一 OS 账户或 Agent 触达
范围之外的审批守护进程之后。签名令牌现在携带一次性 nonce,在授权落地点
(apply/start)原子消费;重放、过期或时钟偏移超窗的令牌一律被拒绝。Windows
上锁层回退到 msvcrt 字节范围锁,但真实 Windows 宿主运行仍未记录。
CloudQuant Backtrader 生态:
cloudQuant/backtrader—— 本产品 执行的固定 Backtrader 运行时 fork(commit3c967ed61be184c0099ba5bef55d4bed09ad0b4a)。cloudQuant/backtrader-mcp—— 本 MCP 服务器。cloudQuant/backtrader-skills—— Backtrader 工作流的配套 skills。cloudQuant/backtrader_web—— 配套 Web 产品。cloudQuant/backtrader-agent—— 配套 Agent 产品。cloudQuant/fincore—— FinCore,配套 金融基础设施。
所有命令在本目录下运行:
python -m pip install -e ".[test]"
PYTHONPATH=src python -m pytest -q
ruff check src tests scripts
ruff format --check src tests scripts
PYTHONPATH=src python -m mypy src/backtrader_mcp
# 配合安装章节中的四个 BACKTRADER_MCP_* root 变量:
PYTHONPATH=src python -m backtrader_mcp doctor
PYTHONPATH=src python -m backtrader_mcp audit-independence
python scripts/run_acceptance.py --matrix all \
--require-no-skills --require-no-agent项目依赖固定 cloudQuant/backtrader 的 commit
3c967ed61be184c0099ba5bef55d4bed09ad0b4a,不接受公开 PyPI Backtrader fallback。
测试运行时依次解析显式 BACKTRADER_MCP_TEST_RUNTIME_ROOT、相邻 checkout、已安装包;
每个候选都必须通过 CloudQuant 溯源校验,显式路径无效或不可信时会 fail closed。Ruff 是
唯一 formatter,mypy 是 required 质量门禁。当前分支覆盖率门槛为 80%,以配置中的精确值
作为发布标准。
协议测试只把 mcp==2.0.0 安装到一个临时目标目录,绝不升级或移除用户基础环境的
mcp==1.20.0。固定的验收入口消费一个结构化的 14 格 artifact,而不是从 pytest 进
度点推断成功。它先构建临时 wheel,再根据仓库 constraints 把 wheel 的 [test] 依赖
闭包安装到干净的临时目标,并从本源码检出之外的另一个目录运行 pytest。该 target 必须
包含固定的 CloudQuant Backtrader 分发及匹配的 direct-URL 溯源记录,因此不会借用活动
环境中的产品依赖;backtrader_mcp 本身只从已安装的 wheel target 导入。
矩阵把全部七个 archetype × 两种输出 profile 作为真实的 runonce/runnext 子进程回测
执行,覆盖全部六个 adapter 加 resample/replay,并记录 inspect/register/preview、
draft/validate、prepare/apply、run 和 compare 证据。其 JSON 输出还记录 wheel
SHA-256、已安装模块来源、source_checkout_on_sys_path=false、sibling 产品缺失以及
独立性审计。调用方不能提供任意 pytest 目标。wheel 验收还会验证完整快照的确切
SHA-256,并从本仓库之外的干净临时 site 目录导入 / 搜索它,且 PYTHONPATH 上没有
sibling AI 产品。