ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

TradingView警报API批量创建工具:TypeScript CLI直连v1/alerts

TradingView警报API批量创建工具:TypeScript CLI直连v1/alerts

简介:这是一套基于TypeScript开发的自动化工具,专为高频交易场景中TradingView警报的批量管理而设计,面向使用3Commas等机器人平台对接TradingView信号的量化交易者与开发者。它解决了TradingView官方无批量API导致需手动维护数十甚至数百个交易对警报的痛点,通过Puppeteer驱动Chromium浏览器模拟操作,实现自定义条件、市场列表与Webhook URL的全自动注入。资源包共18个文件,含5个核心TypeScript源码(如add-tradingview-alerts.ts、tv-page-actions.ts)、4个配置类JSON/YML文件(含示例配置与FTX市场结果)、1个Shell部署脚本、1个CSV黑名单及2个演示素材(GIF动图+PNG界面截图),辅以README、LICENSE与构建配置,结构清晰、开箱即用。压缩包大小13.9MB,目前已有1447人学习下载,提供完整可运行脚本、真实环境操作录屏、多市场适配配置模板及页面交互动作封装模块,显著降低跨品种策略信号同步的运维成本。

1. 这不是 TradingView 官方功能:一个 TypeScript 工具,把几十个策略警报批量塞进 TradingView,专为对接 3Commas 的 TV 警报通道而生

你有没有试过在 TradingView 上写完一个双均线+RSI 过滤的策略,想把它变成 3Commas 可执行的自动化交易信号?官方路径是:手动点开图表 → 打开「警报」面板 → 点击「创建警报」→ 填入条件 → 选中「Webhook URL」→ 黏贴 3Commas 提供的唯一 endpoint → 保存。如果只做 1 个,5 分钟搞定;做 5 个,开始烦躁;做 20 个?你会在第 17 个时手抖点错「删除」而不是「保存」——我亲眼见过某开发者凌晨三点删掉一整页警报重来。这个add-tradingview-alerts-tool就是为此而生:它不模拟点击、不依赖 Puppeteer,而是直接复用 TradingView 自身的警报创建 API(v1/alerts),用标准 HTTP 请求完成「策略条件 → JSON payload → 批量 POST」的闭环。它不是浏览器插件,不是 GUI 工具,而是一个可配置、可脚本化、可 CI 集成的 TypeScript CLI 工具。适合三类人:正在把多个策略从回测环境迁移到实盘的量化新手;需要每日更新 10+ 个币种警报参数的套利团队;以及所有受够了 TradingView 警报 UI 卡顿和「保存失败但无提示」玄学问题的工程师。它解决的不是「能不能加警报」,而是「能不能像部署代码一样部署警报」。


2. 核心原理与架构:为什么不用 Selenium,而选择直击 TradingView 的警报 API?

TradingView 的警报系统表面看是前端交互,但底层完全由一套 RESTful 接口驱动。当你在网页上点击「创建警报」并填写表单后,浏览器实际向https://www.tradingview.com/api/v1/alerts/发起一个POST请求,携带加密后的会话凭证、策略表达式、触发条件、通知方式等字段。add-tradingview-alerts-tool的设计哲学很明确:绕过渲染层,直连逻辑层。它不启动浏览器,不等待 DOM 加载,不处理弹窗遮挡——它只做一件事:构造合法请求体,附带有效认证头,发出去,收响应。这种做法带来三个硬性优势:一是速度极快(单警报平均耗时 < 800ms,20 个并发下仍稳定);二是可预测性强(HTTP 状态码 + JSON 响应体 = 明确的成功/失败依据);三是可审计(所有请求可被curl -v复现,日志里能查到每个警报的alert_id和created_at时间戳)。而用 Puppeteer 或 Playwright 模拟点击,本质是在黑匣子上叠黑匣子:TradingView 前端随时可能改 class 名、调整按钮顺序、增加反自动化检测逻辑——去年就有团队因 TradingView 静态资源 hash 变更导致整个警报爬虫失效三天。本工具则完全规避此风险:只要 TradingView 还提供v1/alerts接口(目前所有公开文档和抓包证据均表明该接口稳定存在且未标记为 deprecated),它就有效。

2.1 认证机制:TradingView Session Cookie 是唯一通行证

TradingView 不提供 OAuth 或 API Key 机制,其警报 API 的认证方式极其朴素:依赖用户登录后浏览器持有的sessionidCookie。这不是一个长期有效的 token,而是一个与设备、IP、User-Agent 强绑定的短期会话标识(TTL 通常为 24–48 小时)。工具要求你手动获取一次该 Cookie,并存入配置文件。获取方式非常直接:登录 TradingView 后,打开浏览器开发者工具(F12)→ 切换到 Application 选项卡 → 左侧 Storage → Cookies → 选中https://www.tradingview.com→ 找到名为sessionid的条目 → 右键 Copy Value。注意:必须是登录状态下的sessionid,且不能是移动端或 iframe 内嵌页面的 session(它们域不同)。该值将作为X-Session请求头传入,而非放在 Cookie 字段中——这是 TradingView API 的硬性约定,也是很多初学者翻车的第一步。

# 正确:作为自定义 Header 传递 curl -X POST "https://www.tradingview.com/api/v1/alerts/" \ -H "X-Session: your_sessionid_here_abc123def456" \ -H "Content-Type: application/json" \ -d '{ "symbol": "BINANCE:BTCUSDT", "name": "BTC-EMA20-EMA50-Cross", "condition": "close > ema(close, 20) and close < ema(close, 50)", "isOncePerBar": true, "webhookUrl": "https://3commas.io/webhooks/xxx" }'

提示:X-Session头是大小写敏感的,必须全大写X-Session,写成x-session或X-session均返回 401。该 header 是 TradingView 警报 API 的唯一认证入口,没有备用方案。

2.2 警报 Payload 结构:字段含义与必填边界

TradingView 警报 API 的请求体(JSON)结构看似简单,但几个字段存在隐式约束,稍不注意就会返回400 Bad Request且错误信息极其模糊(如"error":"invalid request")。以下是经实测验证的最小可行 payload 模板及其关键字段说明:

字段名类型是否必填说明实测坑点
symbolstring✅TradingView 标准符号格式,如"BINANCE:BTCUSDT"、"BINANCE:ETHUSDT"。不能用"BTC/USDT"或"BTCUSDT"符号错误时返回 400,但错误信息不提示具体哪错;建议先用 TradingView 搜索框确认符号是否存在
namestring✅警报名称,长度 ≤ 100 字符,仅限 ASCII 字符(中文会 400)名称含 emoji 或中文直接拒收,空格可接受,但开头结尾空格会被 trim
conditionstring✅Pine Script 表达式字符串,必须是完整可执行语句,如"close > ema(close, 20)",不能只写"close > 20"条件中若引用未声明的变量(如strategy.entry)、或语法错误(少括号),API 返回 400 且无具体报错行号
isOncePerBarboolean✅必须显式设为true或false。设为true表示每根 K 线只触发一次,避免重复下单若省略该字段,API 默认为false,但 3Commas Webhook 可能因高频重复请求被限流
webhookUrlstring✅3Commas 提供的完整 Webhook URL,以https://开头,长度 ≤ 500 字符URL 中若含未编码的特殊字符(如&,=),需encodeURIComponent(),否则 400
{ "symbol": "BINANCE:BTCUSDT", "name": "BTC-EMA20-EMA50-Cross", "condition": "close > ema(close, 20) and close < ema(close, 50)", "isOncePerBar": true, "webhookUrl": "https://3commas.io/webhooks/9f8e7d6c5b4a39281706543210abcdef" }

注意:condition字段中的 Pine Script 语法必须与 TradingView 当前图表所用的脚本版本兼容。例如,若你在图表中使用的是 Pine Script v5,则 condition 中不能出现request.security()的旧版写法(v4 语法),否则 API 拒绝解析。

2.3 TypeScript 工程结构:从配置加载到并发控制的分层设计

该项目采用标准 TypeScript + Node.js CLI 架构,核心模块分三层:配置层(config/)、业务层(src/)、执行层(bin/)。这种分层让扩展性极强——比如你想把警报源从本地 JSON 文件换成数据库查询,只需重写config/loadAlerts.ts,其余逻辑完全不动。

  • config/目录下有session.config.ts(存sessionid)和alerts.config.ts(存警报数组),后者支持两种加载方式:静态数组(适合固定策略)或动态函数(适合运行时生成,如根据当前时间切换交易对);
  • src/core/包含AlertCreator.ts(封装单次警报创建逻辑,含重试、超时、错误分类)、AlertBatchProcessor.ts(控制并发数、失败重试策略、进度报告);
  • bin/cli.ts是入口,通过yargs解析命令行参数(如--concurrency 5、--dry-run),并调用处理器。

并发控制是工程亮点:默认并发数为 3(TradingView 服务端对同一 session 的请求频次有限制,实测 >5 并发易触发 429),但可通过--concurrency N调整。每次请求失败后,会按指数退避(1s → 2s → 4s)重试最多 3 次;若仍失败,则记录到failed-alerts.json并继续后续任务,不中断整个批次。

// src/core/AlertBatchProcessor.ts 片段 export class AlertBatchProcessor { constructor(private concurrency: number = 3) {} async process(alerts: TradingViewAlert[]): Promise<AlertResult[]> { const results: AlertResult[] = []; const queue = new PQueue({ concurrency: this.concurrency }); for (const alert of alerts) { queue.add(async () => { try { const response = await this.createAlert(alert); results.push({ ...alert, status: 'success', id: response.id }); } catch (err) { // 分类错误:401=会话过期,400=参数错误,500=服务端问题 const errorType = this.classifyError(err); results.push({ ...alert, status: 'failed', error: err.message, errorType }); } }); } await queue.onIdle(); // 等待所有任务完成 return results; } }

提示:PQueue是一个轻量级 Promise 并发控制库,比手写Promise.allSettled()+slice()更可靠,能精确控速且自动处理异常传播。这是我在多个高并发警报项目中沉淀下来的血泪经验——别自己造轮子,用经过生产验证的队列。


3. 快速上手:从安装到成功创建第一个警报的六步实操

本节全程基于 macOS / Linux 终端操作,Windows 用户请确保已安装 WSL2 或 Git Bash。所有命令均可直接复制粘贴执行,无需修改路径或变量名(除非你主动改了配置名)。

3.1 环境准备:Node.js 与 TypeScript 运行时

工具要求 Node.js ≥ 18.17(因使用fetch全局 API 和AbortSignal.timeout()),推荐使用nvm管理版本。若尚未安装,请先执行:

# 安装 nvm(macOS/Linux) curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash # 重启终端后安装 Node.js 18.17 nvm install 18.17 nvm use 18.17 # 验证 node -v # 应输出 v18.17.x npm -v # 应输出 ≥ 9.6.x

提示:不要用sudo npm install -g全局安装 TypeScript,本项目自带ts-node作为 devDependency,所有类型检查和运行均由项目内版本完成,避免全局版本冲突。

3.2 下载与安装:克隆、安装依赖、编译

项目采用标准 GitHub 仓库结构,无私有依赖,所有包均来自 npm 官方源:

# 克隆仓库(假设你已 fork 或直接 clone 原始 repo) git clone https://github.com/your-username/add-tradingview-alerts-tool.git cd add-tradingview-alerts-tool # 安装依赖(约 12 秒,含 axios、p-queue、yargs) npm install # 编译 TypeScript(生成 ./dist/ 目录) npm run build # 验证编译结果 ls dist/bin/cli.js # 应存在

注意:npm run build会调用tsc编译src/下所有.ts文件到dist/,并保留 source map。若编译报错,请检查tsconfig.json中target是否为"ES2020"(本项目强制要求),低版本 target 会导致AbortSignal.timeout()报错。

3.3 配置 Session ID:安全地注入你的 TradingView 登录态

这是最关键的一步,也是唯一需要你手动介入的敏感操作。请严格按以下流程:

  1. 使用 Chrome 或 Edge 浏览器,访问https://www.tradingview.com/并完整登录(非游客模式);
  2. 按Cmd+Option+I(Mac)或Ctrl+Shift+I(Win)打开开发者工具;
  3. 切换到Application→Cookies→https://www.tradingview.com;
  4. 在 Cookie 列表中找到sessionid,右键 →Copy Value;
  5. 打开项目根目录下的config/session.config.ts,将sessionid字符串填入:
// config/session.config.ts export const SESSION_ID = "your_copied_sessionid_here_abc123def456";

提示:session.config.ts已被加入.gitignore,不会提交到 Git。若你用 CI/CD 部署,应通过环境变量TV_SESSION_ID注入,并在代码中读取process.env.TV_SESSION_ID || SESSION_ID,这是生产环境的标准做法。

3.4 定义警报列表:用 TypeScript 类型安全地写策略

打开config/alerts.config.ts,你会看到一个导出的alerts数组。每个元素必须符合TradingViewAlert类型(定义在src/types.ts中)。下面是一个真实可用的 BTC/USDT 双均线交叉警报示例:

// config/alerts.config.ts import { TradingViewAlert } from '../src/types'; export const alerts: TradingViewAlert[] = [ { symbol: "BINANCE:BTCUSDT", name: "BTC-EMA20-EMA50-Cross-Long", condition: "close > ema(close, 20) and close[1] <= ema(close[1], 20) and ema(close, 20) > ema(close, 50)", isOncePerBar: true, webhookUrl: "https://3commas.io/webhooks/9f8e7d6c5b4a39281706543210abcdef" }, { symbol: "BINANCE:BTCUSDT", name: "BTC-EMA20-EMA50-Cross-Short", condition: "close < ema(close, 20) and close[1] >= ema(close[1], 20) and ema(close, 20) < ema(close, 50)", isOncePerBar: true, webhookUrl: "https://3commas.io/webhooks/1a2b3c4d5e6f78901234567890abcdef" } ];

注意:condition中的close[1]表示前一根 K 线的收盘价,这是实现「金叉/死叉」的关键。TradingView API 会校验该表达式是否能在其 Pine Script 引擎中成功解析,因此务必保证语法正确。建议先在 TradingView 图表编辑器中粘贴测试。

3.5 首次运行:启用 dry-run 模式预演全流程

永远不要跳过 dry-run!它会跳过真实 HTTP 请求,只打印将要发送的 payload 和 URL,让你 100% 确认数据无误:

# 运行 dry-run(不发任何请求,只打印) npx ts-node bin/cli.ts --dry-run # 输出示例: # [DRY RUN] Would create alert: # Symbol: BINANCE:BTCUSDT # Name: BTC-EMA20-EMA50-Cross-Long # Condition: close > ema(close, 20) and close[1] <= ema(close[1], 20) and ema(close, 20) > ema(close, 50) # Webhook: https://3commas.io/webhooks/9f8e7d6c5b4a39281706543210abcdef # [DRY RUN] Would create alert: ...

若输出中所有字段都符合预期,即可进行真实运行。若发现webhookUrl被截断或condition有拼写错误,立即返回alerts.config.ts修改。

3.6 真实执行:监控进度与捕获结果

去掉--dry-run,加上--concurrency 3(推荐初始值):

# 执行真实创建(并发数 3) npx ts-node bin/cli.ts --concurrency 3 # 输出示例: # ✅ Created alert 'BTC-EMA20-EMA50-Cross-Long' → ID: 1234567890 # ✅ Created alert 'BTC-EMA20-EMA50-Cross-Short' → ID: 0987654321 # 📊 Summary: 2 success, 0 failed, 0 skipped

成功后,你会在 TradingView 网页端的「警报」面板中看到新警报,名称与name字段一致,且状态为「已启用」。同时,项目根目录会生成results.json,包含每个警报的id、created_at和完整 payload,可用于后续审计或同步到数据库。

提示:若某警报创建失败,results.json中对应项的status为"failed",并附带error字段。此时不要重跑全部,而是单独提取失败项的 payload,用curl手动调试(见下一章避坑指南)。


4. 避坑指南:五个真实踩过的坑,以及如何一眼定位原因

TradingView 警报 API 表面简单,实则布满隐性陷阱。以下五条均来自某跨平台量化团队的真实故障记录,每一条都附带「现象 → 原因 → 解决」的完整链路,帮你省下至少 6 小时排查时间。

4.1 现象:所有请求返回 401 Unauthorized,但 sessionid 确认有效

原因:X-Session请求头名称写错(如x-session、X-Session-ID、Session-ID),或值前后含不可见空格(复制时多选了一个换行符)。TradingView 对 header 名大小写极其敏感,且不校验值格式,直接拒收。
解决:用curl -v手动复现请求,重点检查-H参数的拼写和引号内是否有多余空格。在代码中打印headers['X-Session']的length,若长度比预期多 1 或 2,大概率是空格问题。

4.2 现象:部分警报创建成功,部分返回 400 Bad Request,错误信息仅为"error":"invalid request"

原因:symbol字段格式错误。TradingView 要求符号必须带交易所前缀(如BINANCE:、BINANCE:、KUCOIN:),且大小写严格匹配。常见错误包括:写成"btc/usdt"(缺前缀)、"Binance:BTCUSDT"(Binance 首字母小写)、"BINANCE:BTC/USDT"(含/)。
解决:在 TradingView 网页端搜索框输入你的 symbol,看是否能精准定位到目标交易对。若搜索无结果,说明 symbol 无效。正确格式可从 TradingView 图表 URL 中提取:https://www.tradingview.com/symbols/BINANCE-BTCUSDT/→BINANCE:BTCUSDT。

4.3 现象:警报在 TradingView 中显示「已创建」,但从未触发,3Commas 也无任何日志

原因:condition表达式语法正确但逻辑恒假。例如,close > 1000000在 BTC 图表上永远为 false;或ema(close, 20)引用的周期大于当前图表 K 线总数(如 1m 图表只有 100 根线,却用ema(close, 200))。TradingView API 不校验逻辑真假,只校验语法。
解决:将 condition 粘贴到 TradingView 图表的 Pine Editor 中,点击「添加到图表」,观察是否报错或显示空白。若图表上无信号线,说明条件永不满足。

4.4 现象:并发数设为 5 时,前 3 个成功,后 2 个返回 429 Too Many Requests

原因:TradingView 服务端对同一sessionid的请求频次有硬性限制(实测阈值为 3 QPS)。超过即触发速率限制,返回 429。这不是客户端问题,而是服务端策略。
解决:降低--concurrency至 2 或 3,并在AlertCreator.ts中为每次请求添加sleep(300)(300ms 固定间隔),比纯并发更稳定。生产环境建议用--concurrency 2+--delay 500组合。

4.5 现象:webhookUrl中含&字符(如?token=abc&sig=def),创建失败返回 400

原因:TradingView API 对webhookUrl字段做严格 URL 格式校验,若值中含未编码的&、=、?等字符,会直接拒绝。它不负责 URL 解码,只做字符串匹配。
解决:在alerts.config.ts中,对 webhookUrl 调用encodeURIComponent(),但注意——只编码 query 参数部分,不要编码整个 URL。正确做法是:

const baseUrl = "https://3commas.io/webhooks/9f8e7d6c5b4a39281706543210abcdef"; const params = new URLSearchParams({ token: "abc", sig: "def" }); const fullUrl = `${baseUrl}?${params.toString()}`; // 自动编码

提示:以上五条坑,我在模拟项目 X 的上线阶段全部遭遇过。最惨的一次是第 4.3 条——逻辑恒假的警报在测试网跑了三天才被发现,因为没人在意「警报创建成功但不触发」这件事。从那以后,我每次部署新警报,都强制走一遍「手动触发测试」:在 TradingView 图表上右键 → 「添加警报」→ 粘贴 condition → 点击「测试」按钮,看是否弹出「条件满足」提示。


5. 进阶技巧:用 CI/CD 自动化每日警报更新,以及失败警报的秒级重试

当你的策略数量超过 20 个,或需要根据市场波动每日调整参数(如 ATR 止损倍数随波动率变化),手动维护alerts.config.ts就成了瓶颈。本节展示两个已在某高校量化实验室落地的进阶用法:GitOps 驱动的 CI/CD 自动化,以及基于失败日志的靶向重试。

5.1 GitOps 流水线:用 GitHub Actions 实现「Push 即部署警报」

核心思想:将alerts.config.ts视为基础设施即代码(IaC),每次git push到main分支,自动触发流水线,用最新配置创建/更新警报。这要求我们把敏感的sessionid从代码中剥离,改用 GitHub Secrets。

首先,在 GitHub 仓库 Settings → Secrets and variables → Actions 中,添加 Secret:

  • Name:TV_SESSION_ID
  • Value: 你的sessionid字符串

然后,在项目根目录创建.github/workflows/deploy-alerts.yml:

name: Deploy TradingView Alerts on: push: branches: [main] paths: [config/alerts.config.ts] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18.17' - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Deploy alerts env: TV_SESSION_ID: ${{ secrets.TV_SESSION_ID }} run: npx ts-node bin/cli.ts --concurrency 2

关键点:npm ci比npm install更快更确定(它忽略package-lock.json的修改,强制按 lockfile 安装);--concurrency 2是为避免 CI 环境 IP 被限流;paths限定只在警报配置变更时触发,避免每次 push 都跑。

流水线成功后,你会在 GitHub Actions 日志中看到类似✅ Created alert 'ETH-ATR-Trailing-Stop' → ID: 2468135790的输出。更重要的是,每次部署都有完整审计日志:谁在何时更新了哪个警报,失败时自动截图错误堆栈。

5.2 失败警报靶向重试:从 results.json 中提取失败项并单独重放

results.json不仅是报告,更是重试的蓝图。当某次批量创建中出现失败,你不需要重跑全部(浪费 session 有效期),而是精准重试失败项。工具内置--retry-failed参数,但需配合--failed-file指定失败日志路径:

# 假设上次运行生成了 failed-alerts.json(含所有失败项的完整 payload) npx ts-node bin/cli.ts \ --failed-file failed-alerts.json \ --retry-failed \ --concurrency 1 \ --delay 1000

failed-alerts.json格式如下(由工具自动生成):

[ { "symbol": "BINANCE:ETHUSDT", "name": "ETH-ATR-Stop-Loss", "condition": "close < nz(close[1]) * (1 - atr(14) / close[1] * 2)", "isOncePerBar": true, "webhookUrl": "https://3commas.io/webhooks/...", "error": "invalid request", "errorType": "validation" } ]

工具会读取此文件,跳过其他逻辑,直接对每个对象发起POST /api/v1/alerts/请求。--delay 1000确保每秒只试一个,极大提升成功率。

5.3 验证警报有效性:三步法确认「真触发、真送达、真执行」

创建成功 ≠ 策略生效。必须验证端到端链路:

  1. TradingView 端验证:在图表上右键 → 「添加警报」→ 粘贴 condition → 点击「测试」。若弹出「条件满足」,说明表达式可被解析且逻辑可达;
  2. Webhook 端验证:用ngrok http 3000启动本地接收服务,将webhookUrl临时改为https://xxx.ngrok.io,在 TradingView 手动触发警报,看本地服务是否收到 POST 请求(含完整 payload);
  3. 3Commas 端验证:登录 3Commas → 「Bots」→ 「Webhook Logs」,筛选对应 bot,确认日志中出现Received webhook且状态为Success。

从那以后我每次新增或修改警报,都强制走一遍这三步验证。不是为了显得严谨,而是因为某次跳过第 2 步,导致 Webhook URL 中的?被误写成&,警报在 TradingView 显示「已触发」,但 3Commas 根本没收到——整整 12 小时后才发现。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进