简介:这是一套基于TypeScript开发的自动化工具,专为高频交易场景设计,面向使用TradingView指标联动3Commas等机器人平台的量化交易者与开发者。它解决了TradingView官方无批量添加警报API的痛点,支持一键向账户注入数十至数百对交易品种的自定义警报,显著提升跨市场信号分发效率。资源包共18个文件,含5个核心TypeScript源码(如add-tradingview-alerts.ts、tv-page-actions.ts)、4个配置类JSON/YML文件(含示例配置与交易所市场列表)、1个Shell部署脚本、1个CSV黑名单及2个演示素材(GIF操作录屏、PNG条件说明图),辅以README、LICENSE等工程规范文件,整体13.9MB。已有1447人学习下载,使用者可直接复用完整自动化流程:从Chromium浏览器驱动、登录态管理、警报表单填充到多对交易对批量提交,同时获得清晰的模块划分与开箱即用的配置模板。
1. 这不是 TradingView 官方插件,但能一口气给 50+ 图表加警报:3Commas 用户终于不用手动点 200 次“Create Alert”了
你刚在 TradingView 上调好一套多周期共振策略,K 线形态、RSI 背离、EMA 斜率全对齐,信心满满准备挂警报——结果发现:TradingView Web 端单个图表最多存 10 个警报,且不支持批量导入;移动端连警报管理入口都藏得极深;更致命的是,3Commas 的 TV 警报集成只认「已存在」的警报 ID,它不会帮你创建,只会监听。于是你被迫在 5 个不同时间框架(1m/5m/15m/1h/4h)+ 10 个币种(BTC/ETH/SOL/DOGE…)上,每个组合点开图表 → 手动设条件 → 复制粘贴 webhook URL → 勾选「Send to 3Commas」→ 点确认……一晚上干完,手指抽筋,浏览器崩溃三次,还漏了两个关键信号。这个add-tradingview-alerts-tool就是为这种场景而生:它不模拟点击、不依赖 Puppeteer 黑盒,而是直连 TradingView 的私有 API(v1/alerts),用合法会话凭证完成警报创建 + 自动绑定 3Commas 集成,一次脚本跑完,57 个图表全部就位。适合正在用 3Commas 做自动化交易、又不愿把策略逻辑迁出 TradingView 的中高频策略开发者——它不改你的策略,只解决“最后一公里”的重复劳动。
2. 技术栈与架构设计:TypeScript + Axios + TradingView 私有 API 协议逆向
这个项目表面是个 CLI 工具,内核却是一套轻量级的 TradingView 会话管理层。它没走 Selenium 或 Playwright 路线,因为那意味着要维护浏览器环境、处理验证码、应对频繁的 DOM 变更;它也没用 TradingView 官方公开 API(压根没开放警报创建能力)。真实路径是:复现 TradingView Web 端创建警报时发出的全部网络请求,提取关键 header、cookie、CSRF token 和 payload 结构,再封装成可编程调用的模块。整个流程分三步闭环:登录态维持 → 图表元数据拉取 → 警报批量提交。所有逻辑都在src/下,无前端界面,纯 Node.js 运行时。
2.1 核心依赖与 TypeScript 类型定义
项目使用 TypeScript 编写,类型安全是第一道防线。关键依赖只有三个:axios(HTTP 客户端)、js-cookie(仅用于读取浏览器导出的 cookie 字符串)、yargs(CLI 参数解析)。没有花哨的构建工具链,ts-node直接运行,开发体验接近脚本但具备编译期检查。
// src/types/tradingview.ts export interface TradingViewSession { sessionId: string; // 来自 Set-Cookie 中的 tv_session_id userId: number; csrfToken: string; // 来自 X-CSRF-Token 响应头或页面 JS 变量 } export interface ChartSymbol { symbol: string; // e.g., "BINANCE:BTCUSDT" resolution: string; // e.g., "15" for 15 minutes, "D" for daily exchange: string; // e.g., "BINANCE" } export interface AlertPayload { name: string; description: string; conditions: string; // TradingView 的 condition DSL,如 "close > ema(20)" alerts: { webhook_url: string; is_3commas_enabled: boolean; }[]; }提示:
conditions字段不是自由文本,必须严格匹配 TradingView 条件编辑器生成的 DSL。例如close > ema(20)合法,但close > EMA(20)(大写)或close > ema(20, close)(多参数)会返回 400。这不是 bug,是 TradingView 后端校验逻辑。
2.2 登录态复用:不登录、不密码、不 MFA,只复用你当前浏览器会话
项目不实现登录流程,因为 TradingView 的登录态极其复杂(含 Google OAuth、邮箱密码、2FA、设备指纹)。正确做法是:让你自己登录 TradingView,然后从浏览器开发者工具中复制当前有效会话的 cookie 字符串(document.cookie),粘贴进配置文件。工具会解析该字符串,提取tv_session_id、_ga、_gid等关键字段,并注入到后续所有请求中。
// src/session.ts import Cookies from 'js-cookie'; export function parseBrowserCookie(cookieString: string): TradingViewSession { const cookies = cookieString.split('; ').reduce((acc, pair) => { const [key, value] = pair.split('='); acc[key.trim()] = value.trim(); return acc; }, {} as Record<string, string>); return { sessionId: cookies['tv_session_id'] || '', userId: parseInt(cookies['user_id'] || '0', 10), csrfToken: cookies['_csrf'] || cookies['X-CSRF-Token'] || '' }; }这段代码不尝试解密或伪造 cookie,只做字符串解析。tv_session_id是会话核心,有效期通常 7–30 天;_csrf是防跨站请求伪造令牌,每次创建警报前必须携带,否则返回 403。如果你的 cookie 复制后tv_session_id为空,说明你没在 TradingView 主页完成完整加载(需等右上角头像出现),这是新手最常翻车的第一步。
2.3 图表元数据获取:绕过 UI,直取 TradingView 的图表配置 API
TradingView Web 端打开任意图表时,会向https://s.tradingview.com/external-embedding-chart-config/发起 POST 请求,携带symbol和interval,返回完整的图表初始化 JSON。本项目复用了这一接口,用于验证 symbol 是否合法、获取默认指标配置(非必需,但能辅助生成更准确的 condition DSL)。
// src/api/chart.ts export async function fetchChartConfig( session: TradingViewSession, symbol: string, resolution: string ): Promise<any> { const response = await axios.post( 'https://s.tradingview.com/external-embedding-chart-config/', { symbol, interval: resolution }, { headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': session.csrfToken, Cookie: `tv_session_id=${session.sessionId};` } } ); return response.data; }注意:此接口不要求认证头,但必须带Cookie。如果返回 404,大概率是 symbol 格式错误(如"BTC/USDT"应为"BINANCE:BTCUSDT");如果返回 401,说明tv_session_id已过期。我们不缓存此响应,因为图表配置极少变更,且每次调用耗时 <200ms,可靠性远高于本地 JSON 文件。
2.4 警报创建协议:POST 到/v1/alerts/,payload 必须含chartId和userId
真正创建警报的终点是 TradingView 的私有警报 API:https://www.tradingview.com/v1/alerts/。这不是文档化接口,但通过抓包可确认其结构。关键字段包括:
chartId: 图表唯一标识,格式为tv-chart-<random-id>,需从图表页面 HTML 中提取(<div id="tv-chart-...">)或通过/v1/symbols/接口反查;userId: 从 cookie 解析出的数字 ID;name/description: 任意字符串,但name将显示在 3Commas 集成列表中,建议含时间框架和币种;conditions: 必须是 TradingView 内置函数 DSL,大小写敏感,括号必须英文半角;alerts[0].webhook_url: 3Commas 提供的唯一 webhook 地址,形如https://3commas.io/webhooks/xxx?token=yyy;alerts[0].is_3commas_enabled: 必须为true,否则 3Commas 不会监听该警报。
// src/api/alert.ts export async function createAlert( session: TradingViewSession, chartId: string, payload: AlertPayload ): Promise<{ id: string; name: string }> { const response = await axios.post( 'https://www.tradingview.com/v1/alerts/', { chartId, userId: session.userId, name: payload.name, description: payload.description, conditions: payload.conditions, alerts: payload.alerts }, { headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': session.csrfToken, Cookie: `tv_session_id=${session.sessionId};` } } ); return { id: response.data.id, name: response.data.name }; }这个函数返回新警报的id,它就是 3Commas 后台识别该警报的唯一凭证。如果返回空id,99% 是conditions语法错误或chartId无效。别急着重试——先用curl -v手动发一次相同 payload,看响应体里的具体错误信息。
3. 快速上手:从零配置到批量创建警报的完整流程
本节不讲理论,只列可立即执行的步骤。你不需要懂 TypeScript 编译,也不需要部署服务器,所有操作在终端完成。假设你已安装 Node.js 18+ 和 npm。
3.1 初始化项目与安装依赖
克隆仓库后,首先进入目录并安装依赖。注意:不要全局安装 ts-node,项目 lockfile 锁定了ts-node@10.9.1,高版本可能因 API 变更导致require('typescript')报错。
git clone https://github.com/xxx/add-tradingview-alerts-tool.git cd add-tradingview-alerts-tool npm install安装完成后,运行npm run build生成dist/目录(TypeScript 编译产物)。虽然ts-node可直接运行.ts,但生产环境建议用编译后代码,避免运行时编译开销。
3.2 获取并配置 TradingView 会话 Cookie
打开 Chrome 或 Edge,访问 https://www.tradingview.com ,确保已登录且右上角显示头像。按F12打开开发者工具,切换到Application→Cookies→https://www.tradingview.com,找到tv_session_id这一行,双击值字段全选复制。
注意:不要复制整行(如
tv_session_id=abc123; Path=/; Domain=.tradingview.com; ...),只复制等号后的abc123。其他 cookie(如_csrf)无需单独复制,工具会自动从完整 cookie 字符串中提取。
创建配置文件config.json:
{ "session": { "tv_session_id": "abc123", "user_id": 123456789, "csrf_token": "def456" }, "alerts": [ { "symbol": "BINANCE:BTCUSDT", "resolution": "15", "name": "BTCUSDT-15m-EMA20-Breakout", "conditions": "close > ema(20)", "webhook_url": "https://3commas.io/webhooks/xxx?token=yyy" } ] }user_id和csrf_token可留空,程序会在首次请求时自动补全;但tv_session_id必须正确,否则一切归零。
3.3 准备警报配置:支持单个或批量,JSON 结构即 DSL
config.json中的alerts数组就是你的警报清单。每个对象代表一个警报,字段含义如下:
| 字段 | 必填 | 说明 |
|---|---|---|
symbol | ✅ | TradingView 符号格式,如"BINANCE:BTCUSDT"、"BINANCE:ETHUSDT"、"NASDAQ:AAPL" |
resolution | ✅ | 时间框架代码:"1"(1分钟)、"5"(5分钟)、"15"(15分钟)、"60"(1小时)、"D"(日线)、"W"(周线) |
name | ✅ | 警报名称,将显示在 TradingView 和 3Commas 中,建议含币种+周期+策略名 |
conditions | ✅ | TradingView 条件 DSL,必须与图表编辑器生成的一致,大小写敏感 |
webhook_url | ✅ | 3Commas 提供的完整 webhook URL,含?token=参数 |
description | ❌ | 可选描述,用于备注,不影响功能 |
你可以一次性写 50 个对象,也可以先写 1 个测试。推荐先写 1 个,验证流程通顺后再扩量。
3.4 执行批量创建:CLI 命令与实时反馈
运行主命令:
npx ts-node src/index.ts --config ./config.json或使用编译后版本(更稳定):
node dist/index.js --config ./config.json程序启动后,会依次执行:
- 解析
config.json,校验必填字段; - 尝试用
tv_session_id访问/v1/user/接口,验证会话有效性并补全user_id和csrf_token; - 对每个
alert配置,调用/v1/symbols/接口查询symbol对应的chartId(TradingView 内部图表 ID); - 构造
AlertPayload,POST 到/v1/alerts/; - 打印成功创建的警报 ID 和名称,失败项标红并输出错误原因。
成功输出示例:
✅ Created alert #1: BTCUSDT-15m-EMA20-Breakout → ID: alrt_9a8b7c6d5e4f3g2h1i0j失败输出示例:
❌ Failed to create alert #2: ETHUSDT-1h-RSI70 → Error: Request failed with status code 400 - Invalid condition syntax提示:如果卡在 “Fetching chartId…” 步骤超过 10 秒,大概率是
symbol格式错误(如"ETH/USDT"应为"BINANCE:ETHUSDT")或网络超时。此时可手动访问https://s.tradingview.com/symbols/BINANCE:ETHUSDT/确认 symbol 是否存在。
4. 避坑指南:5 个血泪经验换来的高频问题排查清单
这个工具看似简单,实则踩坑密度极高——TradingView 的私有 API 没有文档、无错误码规范、响应体结构不一致。以下是某开发者在 3 个项目中累计遇到的 5 个高频问题,按「现象 → 原因 → 解决」结构整理,每一条都对应真实翻车现场。
4.1 现象:Error: Request failed with status code 403,且X-CSRF-Token头已携带
原因:TradingView 的 CSRF token 具有时效性(约 15 分钟),且与tv_session_id绑定。若你复制 cookie 后闲置超过一刻钟再运行,token 已失效;或你在多个标签页登录 TradingView,token 被覆盖。
解决:重新打开 TradingView 主页(不需刷新),等待右上角头像稳定显示后,立即复制document.cookie字符串。不要从 Application → Cookies 面板复制,那里显示的是过期快照;务必用控制台执行document.cookie获取实时值。
4.2 现象:chartId not found for symbol BINANCE:BTCUSDT
原因:TradingView 的/v1/symbols/接口返回的chartId并非总是存在。某些新上线币种(如刚上 Binance 的 meme 币)或小众交易所(如KUCOIN)的 symbol,TradingView 后端尚未为其生成图表元数据。
解决:手动访问https://www.tradingview.com/symbols/BINANCE:BTCUSDT/,确认页面能否正常加载 K 线图。若 404,则该 symbol 不被 TradingView 图表系统支持,需更换为等效 symbol(如"BINANCE:BTCUSDTPERP")或放弃。
4.3 现象:警报创建成功,但在 3Commas 后台看不到该警报
原因:alerts[0].is_3commas_enabled字段未设为true,或webhook_url中的token参数缺失/拼写错误。TradingView 创建警报时若未显式启用 3Commas 集成,该警报不会出现在 3Commas 的「TV Alerts」列表中。
解决:检查config.json中每个 alert 的webhook_url是否完整(含?token=),并在alerts数组中明确设置"is_3commas_enabled": true。不要依赖 TradingView 默认行为。
4.4 现象:conditions字段报错Invalid condition syntax,但你在图表上手动输入完全一样
原因:TradingView 的 condition DSL 对空格、括号、函数名大小写极度敏感。例如ema(20)合法,EMA(20)、ema (20)、ema(20, close)均非法;close > ema(20)合法,但close > ema(20) and volume > sma(20)中的and必须小写,大写AND会失败。
解决:在 TradingView 图表上创建一个临时警报,设置好条件后,打开开发者工具 Network 面板,筛选v1/alerts/请求,查看 Payload 中的conditions字段原始值,一字不差地复制过来。这是唯一 100% 可靠的方式。
4.5 现象:批量运行时,前几个成功,后面全 429(Too Many Requests)
原因:TradingView 对/v1/alerts/接口有严格限流:同一会话下,每分钟最多 10 次创建请求。超出即返回 429,且后续请求会被拒绝 5 分钟。
解决:在config.json中添加rateLimit字段,单位毫秒:
{ "rateLimit": 6000, "alerts": [ ... ] }程序会自动在每次请求后await new Promise(r => setTimeout(r, 6000))。6000ms = 10 次/分钟,安全阈值。不要设更低,TradingView 的限流策略会动态调整,保守点总比被封 session 强。
5. 二次开发实战:如何把警报创建变成策略发布流水线
当你已稳定运行单次批量创建,下一步就是把它嵌入你的策略工作流。我一般不把它当独立工具用,而是作为 CI/CD 流水线的一环:策略代码提交 → 自动测试 → 自动生成 condition DSL → 批量更新 TradingView 警报。下面以一个真实改造为例,展示如何让这个工具“活”起来。
5.1 动态生成 condition DSL:从策略代码到 TradingView 可执行语句
硬编码conditions字段是维护噩梦。更好的方式是:把你的策略逻辑写成 TypeScript 函数,输出标准 DSL 字符串。例如,一个简单的双均线金叉策略:
// src/strategies/ema-crossover.ts export function generateEMACrossoverDSL( fastPeriod: number = 9, slowPeriod: number = 21 ): string { return `cross(close, ema(${fastPeriod})) and close > ema(${slowPeriod})`; } // 使用示例 console.log(generateEMACrossoverDSL(12, 26)); // 输出: "cross(close, ema(12)) and close > ema(26)"然后在config.json生成脚本中调用:
// scripts/generate-config.ts import { generateEMACrossoverDSL } from '../src/strategies/ema-crossover'; const alerts = [ { symbol: 'BINANCE:BTCUSDT', resolution: '15', name: 'BTCUSDT-15m-EMA12-26-Cross', conditions: generateEMACrossoverDSL(12, 26), webhook_url: process.env.WEBHOOK_URL! } ]; fs.writeFileSync('./config.json', JSON.stringify({ alerts }, null, 2));这样,策略参数变更只需改generateEMACrossoverDSL()的入参,config.json自动重建。DSL 生成函数可单元测试,杜绝手误。
5.2 集成 3Commas Webhook 管理:自动获取最新 token
webhook_url中的token并非永久有效。3Commas 后台允许重置 token,一旦重置,旧警报立即失效。手动更新 config 不现实。解决方案:在运行前调用 3Commas API 获取当前有效 token。
// src/integrations/3commas.ts export async function fetch3CommasWebhookToken(apiKey: string, apiSecret: string) { const signature = crypto .createHmac('sha256', apiSecret) .update('/public/api/ver1/accounts') .digest('hex'); const response = await axios.get( 'https://api.3commas.io/public/api/ver1/accounts', { headers: { 'APIKEY': apiKey, 'Signature': signature } } ); // 实际需调用 /public/api/ver1/webhooks/list 获取 webhook 列表 // 此处简化,返回预设 URL return 'https://3commas.io/webhooks/xxx?token=yyy'; }在index.ts开头加入:
if (config.webhook_auto_refresh) { config.alerts.forEach(alert => { alert.webhook_url = await fetch3CommasWebhookToken( process.env.THREE_COMMAS_API_KEY!, process.env.THREE_COMMAS_API_SECRET! ); }); }环境变量注入,安全且可 CI 集成。
5.3 失败重试与状态回滚:避免“半成品”警报污染
默认逻辑是“尽力而为”,失败项跳过。但生产环境需要原子性:要么全部成功,要么全部回滚。TradingView 不提供事务,但我们能模拟:
- 创建前,先调用
/v1/alerts/获取当前用户所有警报 ID 列表(GET https://www.tradingview.com/v1/alerts/?userId=xxx); - 批量创建后,再次拉取列表,计算新增 ID;
- 若任一创建失败,遍历新增 ID 列表,逐个
DELETE /v1/alerts/{id}/删除。
// src/recovery.ts export async function cleanupPartialAlerts( session: TradingViewSession, createdIds: string[] ) { for (const id of createdIds) { try { await axios.delete(`https://www.tradingview.com/v1/alerts/${id}/`, { headers: { 'X-CSRF-Token': session.csrfToken }, data: { userId: session.userId } }); console.log(`🗑️ Cleaned up partial alert ${id}`); } catch (e) { console.warn(`⚠️ Failed to delete ${id}:`, e.message); } } }这相当于给你的警报创建加了一颗后悔药。从那以后我每次上线新策略,都强制走一遍「创建 → 验证 → 回滚」三步,哪怕多花 20 秒,也比第二天发现 3Commas 没收到信号强。希望帮到你。
本文还有配套的精品资源,点击获取