内容
# brainapi-go-sdk
## 简介
一款针对 [WorldQuant BRAIN](https://platform.worldquantbrain.com) HTTP API 的 Go 语言 SDK 及跨平台命令行工具。
- **单二进制命令行工具**,稳定 JSON 输入/输出,可从任何语言脚本调用
- **可导入的库** (`pkg/brainapi`),可嵌入到其他 Go 程序中
- **TLS 伪装**,通过 [`bogdanfinn/tls-client`](https://github.com/bogdanfinn/tls-client) 实现(Chrome 131 默认;Safari / Firefox 配置文件可用)
- **Altcha PoW 验证码** 解决器,用于 `POST /users`(并行 SHA-256,运行时.NumCPU 工作线程)
- **生产级重试策略**:浮点解析 `Retry-After`,401 自动重新登录,403 禁用检测,503 长轮询提交/模拟,连续模拟提示冷却
## 安装
**前提条件:** [WorldQuant BRAIN](https://platform.worldquantbrain.com) 账户(`register` 命令可创建账户),以及构建源码所需的 Go 1.26.1+(通过 `go version` 检查)。如果您直接获取预编译二进制文件,则无需满足这些条件。
```bash
# 库
go get github.com/wh0amibjm/brainapi-go-sdk/pkg/brainapi
# 命令行工具(Go 1.26+)
go install github.com/wh0amibjm/brainapi-go-sdk/cmd/brainapi@latest
```
或者,从 [**Releases**](https://github.com/wh0amibjm/brainapi-go-sdk/releases) 页面下载适用于您平台的预编译二进制文件及其 `SHA256SUMS.txt` 文件。要在本地构建,请运行 `make release`,二进制文件将位于 `bin/` 目录中。
## 命令行工具快速入门
```bash
# 设置凭证(或在每个命令中传递 --user / --pass)
export BRAINAPI_USER=me@example.com
export BRAINAPI_PASS=hunter2
# 探测实时会话(自动登录,401 错误时)
brainapi auth probe
# 获取一个 alpha
brainapi alphas get qMPjAxnO
# 预提交关联门控(免费,无提交预算成本;阈值 0.7)
brainapi alphas corr qMPjAxnO | jq '.data.max'
# 提交并等待结果(长轮询,直到终端)
brainapi alphas submit qMPjAxnO | jq .data
# 枚举操作员目录
brainapi schema operators | jq 'length'
# 查询分层必填数据字段(4 个参数必填)
brainapi schema data-fields --region USA --universe TOP3000 --delay 1
# 排出所有活跃的 alpha,跨所有页面
brainapi alphas list --status ACTIVE --all | jq '.data.count'
# 按值过滤 — 操作员嵌入在字段中,可重复(AND)
brainapi alphas list --status UNSUBMITTED --filter 'is.fitness>=3' --filter 'is.turnover<=0.7' --all | jq '.data.count'
# 获取昨天的提交次数
brainapi users activities submissions --decode | jq '.data.yesterday.value'
```
## 库快速入门
```go
package main
import (
"context"
"fmt"
"log"
"runtime"
"github.com/wh0amibjm/brainapi-go-sdk/pkg/brainapi"
"github.com/wh0amibjm/brainapi-go-sdk/pkg/captcha/altcha"
)
func main() {
cl, err := brainapi.NewClient(brainapi.Options{
Email: "me@example.com",
Password: "hunter2",
Profile: brainapi.ProfileChrome131,
CookieJarPath: "data/cookies.json",
CaptchaSolver: altcha.CaptchaAdapter{Workers: runtime.NumCPU()},
})
if err != nil {
log.Fatal(err)
}
ctx := context.Background()
info, err := cl.Probe(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Printf("logged in as %s (%v)\n", info.User.ID, info.Permissions)
}
```
可运行的示例位于 [`examples/`](examples) 目录中,例如 `go run ./examples/list_active`,以及关联然后提交的门控 (`corr_then_submit`) 和账户注册 (`register_one`,它会创建一个真正的账户)。请先设置 `BRAINAPI_USER` / `BRAINAPI_PASS`。
## 从其他语言集成
如果您从 Node / Python / shell 调用 `brainapi` 作为子进程,而不是在 Go 程序中嵌入 `pkg/brainapi`,请先阅读 [**`docs/sdk-protocol.md`**](docs/sdk-protocol.md)。它定义了稳定的 JSON 信封、退出代码到 `error.kind` 的映射、stdin / `--decode` 约定以及非明显的模式陷阱(`activities.current` 是月度累计而不是今日;BRAIN 日在 3 AM ET 时间滚动;等)。
捆绑的 TypeScript 客户端位于 [`clients/typescript/`](clients/typescript) 目录中,是参考包装器 - 请查看其信封解析器、类型化异常层次结构和依赖项免费的子进程(`child_process.spawn`)管道。
## MCP 服务器
对于 AI 代理,`cmd/brainapi-mcp` 通过 stdio 将相同的 SDK 作为 [MCP](https://modelcontextprotocol.io) 服务器暴露出来 - 没有子进程调用,它直接嵌入 `pkg/brainapi`。
```bash
go install github.com/wh0amibjm/brainapi-go-sdk/cmd/brainapi-mcp@latest
# 或本地构建:make build-mcp → bin/brainapi-mcp
```
(或从 [Releases](https://github.com/wh0amibjm/brainapi-go-sdk/releases) 页面获取预编译的 `brainapi-mcp-<version>-<os>-<arch>` 二进制文件。)
使用标准配置块将其注册到任何 MCP 客户端。凭证位于 `env` 块中(服务器读取 `BRAINAPI_USER` / `BRAINAPI_PASS`);所有日志输出到 stderr,因此 stdout 保持纯 JSON-RPC:
```json
{
"mcpServers": {
"brainapi": {
"command": "/path/to/brainapi-mcp",
"args": [],
"env": {
"BRAINAPI_USER": "me@example.com",
"BRAINAPI_PASS": "hunter2"
}
}
}
}
```
**默认情况下为只读。** 服务器注册 **20 个只读(GET)工具**(`probe`、`whoami`、`operators`、`get_alpha`、`check_alpha`、`self_correlation`、`alpha_pnl`、`list_alphas`、`data_fields`、`get_simulation` 等)以及 `report_issue` - 一个用于报告 SDK 本身缺陷的始终开启的代理反馈通道(独立于 `--enable-writes`,并由 `confirm=true` 控制,而无需令牌它只会返回一个点击文件草稿 URL)- 因此默认界面是 **21 个工具**。**10 个变异工具**(`submit_alpha`、`simulations_create`、`register`、`login`、`logout`、`email_verify`、`email_reverify`、`password_forgot`、`password_reset`、`persona_complete`)**仅在您在 `args` 中传递 `--enable-writes`** 时注册(共 31 个工具)。`submit_alpha` 甚至在这种情况下也是双重控制的:它首先运行自相关门控(`max < 0.7`),并且需要 `confirm=true`,否则它会返回一个 dry-run,并且不会花费每日时间槽。
在发生错误时,每个工具都会返回一个 `isError` 结果,其内容是一个结构化的 `{kind, message, details}` JSON 有效载荷 - 与 CLI 公开的相同错误分类法(`rate_limit`、`budget`、`banned`、`drf_validation` 等)- 因此代理可以根据 `kind` 进行分支,而不是解析消息。需要请求正文的变异工具(`simulations_create`、`register`)接受它为类型化对象,具有真正的输入模式,而不是不透明的 JSON 字符串。
## 代理技能
对于 [Claude Code](https://docs.claude.com/claude-code) 和其他 Claude 家族代理,安装的 **代理技能** 将 CLI 与判断力和安全轨道(发现优先,通过 `describe`、退出代码分支和关联控制的 `safe-submit` 助手)包装起来。单命令安装:
```bash
make install-skill # 安装到 ~/.claude/skills
# 或,独立: bash clients/skill/install.sh
```
查看 [`clients/skill/`](clients/skill) 以获取 SKILL.md 以及它在原始 CLI 之上添加的内容。
## 我应该使用哪种集成方式?
| 您是… | 使用 | 添加了什么 | 需要 |
|---|---|---|---|
| 一个具有 MCP 能力的代理/主机(Claude Desktop, Cursor, …) | **MCP 服务器** ([`cmd/brainapi-mcp`](cmd/brainapi-mcp)) | 类型化的工具,默认为只读,结构化错误 - 无 shell | `brainapi-mcp` 二进制文件 |
| 在 Claude Code 上构建 | **代理技能** ([`clients/skill`](clients/skill)) | CLI 界面 + 判断 / 安全轨道 | `brainapi` 二进制文件,`jq`,shell |
| 从 Node / Python / shell 脚本 | **CLI 作为子进程**(参见 [`docs/sdk-protocol.md`](docs/sdk-protocol.md)) | 稳定的 JSON 信封 + 退出代码,任意语言 | `brainapi` 二进制文件 |
| 嵌入到 Go 程序中 | **库** ([`pkg/brainapi`](pkg/brainapi)) | 类型化的方法,完全控制 | Go 1.26.1+ |
## 端点覆盖率
每个记录的 BRAIN 端点都以 1:1 的比例包装为库方法和 CLI 子命令。**示例** 列链接到 `testdata/` 中的规范响应夹具 - 包装器可以使用这些来引导类型化模型,而无需阅读 Go 源代码。
| 端点 | 库方法 | CLI 命令 | 示例 |
|---|---|---|---|
| `POST /authentication` | `Client.Login` | `auth login` | [201 normal](testdata/auth_login_201_normal.json) / [persona](testdata/auth_login_201_persona.json) / [401 invalid](testdata/auth_401_invalid.json) |
| `GET /authentication` | `Client.Probe` | `auth probe` | [secondary](testdata/auth_get_secondary.json) / [401 no-creds](testdata/auth_401_no_creds.json) |
| `DELETE /authentication` | `Client.Logout` | `auth logout` | _(204, no body)_ |
| `POST /authentication/persona` | `Client.CompletePersona` | _(dead-code safety net)_ | — |
| `GET /alphas/{id}` | `Client.GetAlpha` | `alphas get` | [alpha](testdata/alpha_detail.json) |
| `GET /alphas/{id}/check` | `Client.CheckAlpha` | `alphas check` | [terminal](testdata/check_alpha_terminal.json) |
| `POST + GET /alphas/{id}/submit` | `Client.SubmitAlpha` | `alphas submit` | [200 pending](testdata/submit_200_pending.json) / [403 corr-fail](testdata/submit_403_corr_fail.json) |
| `GET /alphas/{id}/recordsets/pnl` | `Client.AlphaPnL` | `alphas pnl` | [pnl](testdata/recordsets_pnl.json) |
| `GET /competitions/{cid}/alphas/{id}/before-and-after-performance` | `Client.BeforeAndAfterPerformance` | `alphas performance --competition <cid>` | [perf](testdata/before_and_after_performance.json) |
| `GET /users/self/alphas` | `Client.ListAlphas` / `ListAlphasAll` | `alphas list [--status] [--filter] [--all]` | [page](testdata/users_alphas_page.json) |
| `POST /simulations` | `Client.CreateSimulation` | `simulations create` | _(returns 201 with `Location` header only)_ |
| `GET /simulations/{id}` | `Client.GetSimulation` / `WaitForSimulation` | `simulations get` / `wait` | [in-progress](testdata/simulation_in_progress.json) / [complete](testdata/simulation_complete.json) |
| `GET /users/self` | `Client.Self` | `users self` | [self](testdata/users_self.json) |
| `GET /users/self/competitions` | `Client.Competitions` | `users competitions` | [competitions](testdata/competitions.json) |
| `GET /users/self/activities/{kind}` | `Client.Activities` + `DecodeActivities` | `users activities` | [simulations (DAILY)](testdata/activities_simulations.json) / [other-payment empty (LIST)](testdata/activities_other_payment_empty.json) |
| `GET /users/self/messages` | `Client.Messages` / `MessagesAll` | `messages list [--all]` | [page](testdata/messages.json) |
| `GET /operators` | `Client.Operators` | `schema operators` | [operators](testdata/operators.json) |
| `GET /data-fields` | `Client.DataFields` / `DataFieldsAll` | `schema data-fields [--all]` | [page](testdata/data_fields_page.json) |
| `POST /users` | `Client.Register` | `register` | _(register success path varies — see captcha leg)_ |
| `POST /user/email/reverify` | `Client.ReverifyEmail` | `email reverify` | _(2xx status, body shape unstable)_ |
| `POST /user/email/verify` | `Client.VerifyEmail` | `email verify` | _(2xx status, body shape unstable)_ |
| `POST /user/password/forgot` | `Client.ForgotPassword` | `password forgot` | _(2xx status, body shape unstable)_ |
| `POST /user/password/reset` | `Client.ResetPassword` | `password reset` | _(2xx status, body shape unstable)_ |
| `GET /captcha` | `Client.FetchCaptchaChallenge` | _(used internally by Register)_ | [challenge](testdata/captcha_challenge.json) |
泛型错误信封示例: [DRF 400](testdata/drf_validation_400.json) 用于 `kind=drf_validation` 形状。
## 配置
| 标志 | 环境变量 | 默认值 | 备注 |
|---|---|---|---|
| `--base-url` | `BRAINAPI_BASE_URL` | `https://api.worldquantbrain.com` | 覆盖用于分段/代理 |
| `--user` | `BRAINAPI_USER` | _(无)_ | 登录和任何需要登录的端点所需 |
| `--pass` | `BRAINAPI_PASS` | _(无)_ | 客户端需要缓存此内容以自动重新登录 |
| `--profile` | _(无)_ | `chrome131` | TLS 伪装;`auto:<email>` 按哈希轮换 |
| `--proxy` | `BRAINAPI_PROXY` | _(无)_ | `http://`, `https://`, 或 `socks5://` |
| `--cookie-jar` | _(无)_ | `${UserCacheDir}/brainapi/cookies-<email>.json` | 文件备份的 jar,具有原子保存 |
| `--timeout` | _(无)_ | `15s` | 每个请求的 HTTP 超时时间 |
| `--log-level` | _(无)_ | `warn` | `error\|warn\|info\|debug` — 输出到 stderr,stdout 输出 JSON |
| `--output` | _(无)_ | `json` | 输出格式(目前仅支持 `json`) |
## 退出代码(CLI)
设计用于 shell 管道。每个代码在 SDK 版本之间都是稳定的。
| 代码 | 含义 |
|---|---|
| 0 | 成功 |
| 2 | 用法错误(错误的标志,缺少必需的参数) |
| 3 | 速率限制或冷却 |
| 4 | 帐户被禁止或未验证 |
| 5 | DRF 字段验证失败(例如注册正文缺少字段) |
| 6 | 通用 API 错误(4xx 没有 DRF 信封,或 5xx 重试后) |
| 7 | 每日预算耗尽(进程门控) |
| 8 | 网络/传输错误 |
| 10 | 登录返回的 Persona 2FA 查询信封(罕见;BRAIN 当前生产中的死代码) |
## BRAIN 协议注意事项(代码中镜像)
这些注意事项 - 由 Chrome DevTools 审计针对 `platform.worldquantbrain.com` 捕获 - 已内置到 SDK 中,因此调用者永远不必考虑它们:
- **`Retry-After` 是浮点秒字符串** (`"5.0"`),而不是整数。 通过 `strconv.ParseFloat` 解析;对于 429 和 503 长轮询,限制在 `[1s, 120s]` 和 `[0.5s, 30s]` 内。
- **`POST /alphas/{id}/check` 返回 405** - 仅限 GET,长轮询 200 + 空正文 + Retry-After。
- **仅 `SELF_CORRELATION` 判决来自 `/alphas/{id}/submit` 长轮询**,而非 `GET /alphas/{id}`(后者无限期保持 `result: "PENDING"`,适用于未提交的 alpha)。
- **`GET /alphas/{id}/correlations/self` 是预提交相关性门控**,并以两种方式发出“仍在计算”信号,具体取决于帐户层级:`503 + Retry-After`(Conditional-Consultant)或 `200 + empty body + Retry-After`(TUTORIAL)。 SDK 选择加入 `longPoll503` 和 `longPoll200Empty`,因此传输层重试任一信号 - 如果没有此双路径,新的 alpha 调用会误导性地返回 `long_poll_exceeded`。 将 `SubmitAlpha` 限制在 `*block.Max < 0.7`(BRAIN 使用的发布后 `SELF_CORRELATION` 检查的相同阈值)以避免浪费每日提交时间槽。
- **`POST /alphas/{id}/submit` 返回 503** 以表示接受,而不是失败 - SDK 将其视为“已排队”,并继续轮询 GET。
- **`POST /alphas/{id}/submit` 针对已进行的提交返回 303** 回到同一 URL(BRAIN 的“仍在处理,请再次轮询”信号),其 `Location` 携带 `http://` 方案(+ `:443`)HTTP/2 传输拒绝的 `http2: unsupported scheme`)。 SDK 禁用重定向跟踪,并将 3xx 视为继续轮询的提示,因此重新提交/轮询恢复不会崩溃。
- **`429` 带有正文 `{"detail":"THROTTLED"}`** 表示 BRAIN 的提交/关联子系统已挂起 - 进行中的 `SELF_CORRELATION` 永不完成,因此可用插槽永不释放,每个提交 429 - 明显与常规速率限制不同。 SDK 在 `rate_limit` 错误的 `details.body` 下显示 429 正文,因此调用者可以将“平台已关闭,请稍后重试”与每个请求的上限区分开来。
- **`GET /operators`** 返回一个裸 JSON 数组; **`GET /data-fields`** 使用 `{count, results}`(无 next/previous); **`GET /users/self/alphas`** 使用完整的 Django REST 信封。 三种不同的形状 - 按端点处理。
- **活动记录 `records.records` 是位置元组**,不是字典。 使用 `DecodeActivities` 通过 `schema.properties` 列映射进行转换。
- **登录时的个人查询信封** (`{"inquiry":"..."}`) 在 BRAIN 当前生产中实际上是死代码,但作为安全网保留(参见 `docs/protocol.md`)。
- **Altcha PoW 验证码** 对于 `POST /users` 是强制性的。 SDK 抓取 `/captcha`,在 `runtime.NumCPU()` 工作线程上并行求解 SHA-256 暴力破解(通常 <60ms),并将 base64 有效载荷注入 `auxiliary.captcha`。
- **BRAIN 日从 3 AM US/Eastern 开始**,而不是午夜。进程内每日预算计数器按相应时间键入。
- **`403` 禁用检测** 在重新登录尝试后计算连续的 403 次。对禁用门控设置 `BanThreshold: 0`。
## 构建
```bash
make all # 编译、测试、构建 CLI 和 MCP 二进制文件(当前平台)
make release # 跨平台编译 CLI 和 MCP 二进制文件(linux x{amd64,arm64}、windows amd64、darwin x{amd64,arm64})
make cover # 覆盖率报告
make install-hooks # 安装 git pre-commit
pre-commit run --all-files # 等效,使用 pre-commit 框架
```
`make build` / `make build-mcp` 只需要 Go 工具链。 `make all`、`make lint`、`make fmt` 和提交钩子还需要以下开发工具:
```bash
go install mvdan.cc/gofumpt@latest # 格式化工具
# golangci-lint v2.x — 参见 https://golangci-lint.run/welcome/install/
pip install pre-commit # 或:uvx pre-commit # 钩子运行器
```
`make vuln` 不需要任何额外内容 - 它通过 `go run` 运行 `govulncheck`。 单一源码树,无 CGO,无平台特定构建标签 - 相同的 `./cmd/brainapi` 包可以干净地编译所有目标。
## 工程标准
- **Lint**:精选的 `golangci-lint` v2 配置 — `errorlint`、`bodyclose`、`gocritic`、`nilerr`、`unparam`、`misspell`、`unconvert` 在标准集之上(`errcheck`、`govet`、`staticcheck`、`ineffassign`、`unused`)- 以及 `gofumpt -extra` 格式化。
- **提交前钩子**:`gofumpt`、`go vet`、`golangci-lint`、`go mod tidy`,以及 Conventional-Commits 主题检查 - 所有这些都在每次提交前运行(完整的 `-race` 测试套件在 CI 和 `pre-push` 上运行)。
- **测试覆盖率**:每个端点方法都有一个由 `httptest.Server` 驱动的单元测试,该服务器重放来自 `testdata/` 的真实 BRAIN 捕获的有效载荷。 重试策略测试涵盖浮点 `Retry-After`、禁令后连续处罚、冷却、DRF 信封解码、长轮询上限。
- **集成测试**:由 `BRAINAPI_INTEGRATION=1` 环境变量控制,因此 CI 不会意外击中生产环境。
## 协议真相
`pkg/brainapi/types.go` 中编码的端点形状镜像了 Chrome-DevTools 验证的响应捕获,这些捕获固定在 [`testdata/`](testdata) 下,并记录在 [`docs/protocol.md`](docs/protocol.md) 中。 当 BRAIN 协议更改时,请重新捕获实时形状,更新夹具和协议注释,然后将更改移植到类型化结构体中。
## 贡献
欢迎提出问题和 PR。 参见 [`CONTRIBUTING.md`](CONTRIBUTING.md) 获取协议合同、提交前门控和测试期望; [`SECURITY.md`](SECURITY.md) 获取如何报告漏洞的信息; 以及 [`CHANGELOG.md`](CHANGELOG.md) 获取发布历史。
## 免责声明
这是 **非官方**、社区构建的客户端,不隶属于、不受 WorldQuant 认可或赞助。 “WorldQuant”和“BRAIN”是其各自所有者的商标,仅在此用于描述 SDK 与之交互的 API。 请遵守平台的服务条款; 您负责如何使用自己的帐户。 软件按“原样”提供,不提供任何形式的保证(参见 [`LICENSE`](LICENSE))。
## 许可证
MIT - 参见 [`LICENSE`](LICENSE)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器