简介:这是一款面向量化交易者与TradingView用户的TypeScript工具,用于批量向TradingView账户添加自定义警报,专为3Commas等平台的TV警报自动交易集成而设计。当交易者需要跨数十甚至上百个交易对维护指标信号时,由于TradingView官方未提供批量添加警报的API,手动操作极为繁琐,该工具借助自动化测试框架驱动内置Chromium浏览器,自动完成警报的批量录入,显著降低重复劳动。资源包共18个文件,约13.9MB,以TypeScript源码为核心,辅以JSON配置、YAML示例、Shell部署脚本及CSV黑名单文件,另附演示GIF与操作截图,便于快速理解运行流程。目前已有1447人学习下载。读者可获得完整的源码工程、配置模板与部署脚本,掌握批量警报自动化的实现思路,并参考示例配置完成本地环境搭建与调试。
1. 批量添加警报到 TradingView:为什么手动点一百次不如写一次脚本
如果你用 3Commas 的 TV 警报功能做过自动化交易,大概率经历过这个场景:策略里配了二十个币对,每个币对要挂三到四条警报——入场、止损、止盈、追踪。打开 TradingView 的警报面板,选图表、填条件、粘 webhook、设过期时间,一条一条来。点完第十条的时候手已经开始机械了,点到第三十条的时候,你大概率会漏掉某个参数,或者把 BTC 的 webhook 粘到了 ETH 的警报里。
add-tradingview-alerts-tool这个方向要解决的就是这件事:把「批量添加警报到 TradingView」从手工劳动变成一次配置、一次执行。它专为 3Commas TV 警报集成设计,核心思路是让脚本替你完成那些重复的、格式固定的警报创建动作。适合两类人:一是手上跑着多币对网格或 DCA 策略、需要定期重建警报的实盘用户;二是想把这套流程接进自己运维管线、做半自动或全自动警报管理的开发者。读完你应该能判断这套方案值不值得搭,以及搭起来之后哪些参数不能乱动。
2. 拆解 TradingView 警报与 3Commas webhook 的对接逻辑
2.1 一条警报从创建到触发,中间经过了什么
TradingView 的警报本质上是一个「条件 + 动作」的绑定。条件部分由你在图表上选定的指标或价格表达式决定,动作部分则是一段 HTTP 请求——当条件满足时,TradingView 的服务器会向你在警报里填写的 webhook URL 发送一个 POST 请求。对于 3Commas 的 TV 警报集成来说,这个 URL 指向 3Commas 的接收端点,请求体里携带的是一段 JSON,里面包含message字段,而message字段的内容又必须符合 3Commas 定义的信号格式。
这里有一个容易被忽略的细节:TradingView 的警报创建接口并不是一个公开的、文档齐全的 REST API。你在网页端点的每一次「创建警报」,背后是 TradingView 内部的前端请求。批量工具能工作的前提,是它模拟了这些请求的认证态和参数结构。常见做法是复用浏览器会话中的 cookie 和 CSRF token,或者使用 TradingView 提供的有限 API 能力。这意味着批量添加警报的稳定性,很大程度上取决于 TradingView 前端接口的稳定性——它变了,工具就得跟着改。
3Commas 那一侧的要求则相对明确:webhook 收到的 JSON 里,message字段需要包含类似{"action": "buy", "symbol": "BTCUSDT", "price": "..."}这样的结构,具体字段取决于你在 3Commas 里选的信号类型。批量工具要做的,就是为每个币对、每种信号类型,生成对应的message内容,并把它和 TradingView 警报的触发条件绑定在一起。
2.2 为什么选脚本批量而不是 TradingView 自带的批量功能
TradingView 在付费方案里提供了一些警报数量上的便利,但并没有提供「按模板批量创建」的原生功能。你可以在一个图表上复制警报,但复制出来的警报仍然需要逐个修改交易对、条件和 webhook 内容。对于需要跨多个图表、多个时间周期创建警报的场景,手工操作的时间成本是线性增长的。
脚本方案的价值在于三点:第一,配置和动作分离。你把「要监控哪些币对、每个币对用什么信号模板」写进一个配置文件,脚本读取配置后生成警报。第二,可重复执行。策略调整后,你可以清掉旧警报,用同一份配置重新生成,避免手工修改带来的不一致。第三,可校验。脚本在创建之前可以检查参数完整性,比如 webhook 是否为空、价格条件是否合理,减少「创建了但触发不了」的哑警报。
2.3 批量创建警报的三种技术路径对比
| 路径 | 认证方式 | 稳定性 | 适用场景 |
|---|---|---|---|
| 浏览器自动化 | 模拟登录态 | 中,受页面改版影响 | 快速验证,少量警报 |
| 复用会话请求 | Cookie + CSRF | 较高,依赖接口不变 | 日常批量维护 |
| 官方 API(如有) | API Key | 高,但能力受限 | 有官方支持时优先 |
我一般会先走「复用会话请求」这条路,因为它比浏览器自动化轻,又比等官方 API 现实。具体做法是:在浏览器里登录 TradingView,打开开发者工具,抓一次手动创建警报的请求,把请求的 URL、headers、cookies 和 body 结构记录下来。然后写一个脚本,用同样的结构去发请求,只替换掉交易对、条件表达式和 webhook 内容。
注意:会话 cookie 有有效期,过期后脚本会收到 401 或 403。不要把 cookie 硬编码在脚本里长期使用,建议每次执行前从环境变量或本地会话文件中读取。
3. 用 Python 脚本批量创建警报的最小实现
3.1 准备配置文件:把币对和信号模板抽出来
先定义一个 JSON 配置文件,把要创建警报的币对、时间周期、信号类型和 webhook 地址列清楚。这样脚本逻辑和业务数据就分开了,改币对不用动代码。
{ "webhook_url": "https://example.com/webhook/your-3commas-endpoint", "alerts": [ { "symbol": "BTCUSDT", "exchange": "BINANCE", "timeframe": "15", "condition": "crossing", "price": "65000", "message": { "action": "buy", "symbol": "BTCUSDT", "price": "65000" } }, { "symbol": "ETHUSDT", "exchange": "BINANCE", "timeframe": "15", "condition": "crossing", "price": "3200", "message": { "action": "buy", "symbol": "ETHUSDT", "price": "3200" } } ] }webhook_url是 3Commas 给你的接收地址,每个 3Commas 账户的地址不同,不要照抄。alerts数组里每一项对应一条警报。condition字段决定触发方式,常见值有crossing(穿越)、greater_than(大于)、less_than(小于)。message里的内容会作为 webhook 请求体的一部分发给 3Commas,字段名要和你在 3Commas 信号配置里定义的一致。
3.2 构造 TradingView 警报请求
下面这段代码演示如何用requests库发送一个创建警报的请求。注意,这里的 URL 和 headers 结构需要你从自己浏览器的实际请求中抓取后替换,不同账号和地区可能略有差异。
import json import requests # 从浏览器开发者工具中抓取的请求信息 TV_ALERT_ENDPOINT = "https://www.tradingview.com/api/v1/alerts/create/" CSRF_TOKEN = "your_csrf_token_here" SESSION_COOKIE = "your_session_cookie_here" headers = { "Content-Type": "application/json", "X-CSRF-Token": CSRF_TOKEN, "Cookie": f"sessionid={SESSION_COOKIE}", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" } def build_alert_payload(alert_config): """把配置项转换成 TradingView 创建警报所需的请求体""" payload = { "symbol": f"{alert_config['exchange']}:{alert_config['symbol']}", "timeframe": alert_config["timeframe"], "condition": alert_config["condition"], "price": alert_config["price"], "webhook_url": alert_config["webhook_url"], "message": json.dumps(alert_config["message"]), "expiration": "0", # 0 表示不过期 "enabled": True } return payload def create_alert(alert_config): payload = build_alert_payload(alert_config) resp = requests.post(TV_ALERT_ENDPOINT, headers=headers, json=payload, timeout=15) if resp.status_code == 200: print(f"创建成功: {alert_config['symbol']}") else: print(f"创建失败: {alert_config['symbol']} -> {resp.status_code} {resp.text[:200]}") if __name__ == "__main__": with open("alerts_config.json", "r", encoding="utf-8") as f: config = json.load(f) for alert in config["alerts"]: alert["webhook_url"] = config["webhook_url"] create_alert(alert)build_alert_payload负责把配置里的字段映射成 TradingView 接口期望的结构。symbol字段需要带上交易所前缀,比如BINANCE:BTCUSDT,这是 TradingView 识别交易对的标准格式。message字段被序列化成字符串,因为 TradingView 的 webhook 请求体里,message是一个字符串字段,而不是嵌套 JSON。expiration设为"0"表示警报不过期,适合需要长期运行的策略。
create_alert发送请求后检查状态码。200 表示创建成功,401 或 403 通常意味着 cookie 或 CSRF token 失效,需要重新从浏览器获取。429 表示请求频率过高,需要加延时。
3.3 加一层重试和频率控制
批量创建时,连续快速请求容易触发限流。加一个简单的退避逻辑,并在每次请求之间留出间隔。
import time import random def create_alert_with_retry(alert_config, max_retries=3): for attempt in range(max_retries): payload = build_alert_payload(alert_config) resp = requests.post(TV_ALERT_ENDPOINT, headers=headers, json=payload, timeout=15) if resp.status_code == 200: print(f"创建成功: {alert_config['symbol']}") return True elif resp.status_code == 429: wait = (attempt + 1) * 5 + random.uniform(0, 2) print(f"限流,等待 {wait:.1f} 秒后重试: {alert_config['symbol']}") time.sleep(wait) else: print(f"创建失败: {alert_config['symbol']} -> {resp.status_code}") return False return False # 在主循环中调用 for alert in config["alerts"]: alert["webhook_url"] = config["webhook_url"] create_alert_with_retry(alert) time.sleep(1.5) # 每次请求间隔 1.5 秒退避策略是:遇到 429 时,等待时间随重试次数递增,并加一点随机抖动,避免多个脚本同时重试造成二次拥堵。每次成功创建后也留 1.5 秒间隔,这个值可以根据实际限流情况调整。如果警报数量很大,比如超过 50 条,建议把间隔拉到 2 到 3 秒。
4. 避坑:批量警报创建中最容易翻车的五个地方
4.1 警报创建成功但 3Commas 收不到信号
现象:TradingView 警报列表里能看到警报,但触发后 3Commas 没有任何反应。
原因:webhook 请求体里的message字段格式不对。TradingView 发送 webhook 时,会把message字段的内容作为请求体的一部分发出去,但如果你在创建警报时把message设成了一个 JSON 对象而不是字符串,TradingView 可能会把它序列化成带转义的字符串,导致 3Commas 解析失败。
解决:在创建警报时,确保message是一个 JSON 字符串,而不是嵌套对象。用json.dumps()显式转换。创建后,在 TradingView 警报详情里查看 webhook 的实际发送内容,确认格式正确。
4.2 交易对格式不匹配导致警报挂在了错误的图表上
现象:脚本报告创建成功,但警报实际绑定到了默认图表,而不是你期望的交易对。
原因:TradingView 的警报创建接口需要symbol字段带交易所前缀,比如BINANCE:BTCUSDT。如果只写BTCUSDT,接口可能接受请求,但会把警报绑定到当前默认图表或最近打开的图表上。
解决:在配置文件里把交易所和交易对分开存,构造请求时用f"{exchange}:{symbol}"拼接。创建后抽查几条警报,确认绑定的图表和预期一致。
4.3 会话过期导致批量任务中途全部失败
现象:脚本跑到一半开始大量返回 401,前面创建的警报正常,后面的全部失败。
原因:TradingView 的会话 cookie 有有效期,批量任务执行时间较长时,cookie 可能在任务中途过期。
解决:在脚本里检测 401 响应,一旦出现就暂停任务并提示重新获取 cookie。更好的做法是把批量任务拆成小批次,每批之间检查会话状态。如果频繁遇到过期,考虑用 TradingView 的长期 API token(如果有的话)替代会话 cookie。
4.4 重复执行导致警报数量翻倍
现象:第二次运行脚本后,TradingView 里出现了两套相同的警报,触发时 3Commas 收到重复信号。
原因:脚本没有做去重,每次执行都是无条件创建新警报。
解决:在创建之前先拉取现有警报列表,按symbol + condition + price做匹配,已存在的跳过。或者在脚本里维护一个本地记录文件,记录已创建的警报 ID,执行前先读取。更稳妥的做法是每次执行前先清理旧警报,再重新创建,但这要求你有删除警报的接口权限。
4.5 价格条件用了字符串比较导致触发逻辑错误
现象:警报在价格还没到的时候就触发了,或者该触发的时候没触发。
原因:TradingView 的price字段在某些接口版本里期望的是数值类型,传字符串可能导致比较逻辑异常。另外,crossing和greater_than的语义不同,用错了会导致触发时机偏差。
解决:price字段尽量传数值,如果接口要求字符串,确保没有多余的空格或货币符号。crossing表示价格从一侧穿越到另一侧时触发一次,greater_than表示价格大于阈值时持续触发。根据策略需求选择正确的条件类型。
5. 进阶:把警报管理接进日常运维的几个实用技巧
5.1 用模板函数生成不同信号类型的 message
当策略里同时有入场、止损、止盈多种信号时,手写每个message容易出错。写一个模板函数,根据信号类型自动生成对应的 JSON 结构。
def make_message(signal_type, symbol, price=None, percentage=None): """根据信号类型生成 3Commas 可识别的 message 结构""" base = {"symbol": symbol} if signal_type == "entry": base.update({"action": "buy", "price": str(price)}) elif signal_type == "stop_loss": base.update({"action": "sell", "percentage": str(percentage)}) elif signal_type == "take_profit": base.update({"action": "sell", "price": str(price)}) else: raise ValueError(f"未知信号类型: {signal_type}") return base # 使用示例 msg = make_message("entry", "BTCUSDT", price=65000) # 输出: {'symbol': 'BTCUSDT', 'action': 'buy', 'price': '65000'}这个函数把信号类型的差异封装起来,配置文件里只需要写signal_type和对应的价格或百分比,减少手写 JSON 时的字段遗漏。
5.2 创建后自动校验警报状态
批量创建完成后,不要假设全部成功。写一个校验步骤,拉取警报列表,检查每个预期警报是否存在、是否启用、webhook 是否为空。
def verify_alerts(expected_symbols): """拉取当前警报列表,检查预期警报是否都存在""" resp = requests.get(TV_ALERT_ENDPOINT.replace("/create/", "/list/"), headers=headers, timeout=15) if resp.status_code != 200: print("无法获取警报列表,跳过校验") return existing = resp.json().get("alerts", []) existing_symbols = {a.get("symbol") for a in existing} for sym in expected_symbols: if sym not in existing_symbols: print(f"缺失警报: {sym}") else: print(f"确认存在: {sym}")校验步骤能发现那些「接口返回 200 但实际没创建成功」的玄学情况。我一般会在批量任务结束后跑一次校验,把缺失的警报单独补建。
5.3 用定时任务做警报的周期性重建
TradingView 的警报在触发后,如果是一次性警报,会自动失效。对于需要持续监控的策略,可以设置一个定时任务,每天或每周重建一次警报。这样即使某条警报因为触发而失效,下一次重建会把它补回来。
定时任务的频率取决于策略的调整周期。如果策略参数每天变,就每天重建;如果策略稳定,可以每周重建一次。重建前先清理旧警报,避免重复。清理操作需要删除接口的权限,如果接口不支持删除,可以先把旧警报禁用,再创建新的。
5.4 把配置文件和版本管理结合起来
警报配置是一份有价值的资产,它记录了你当前监控的币对、价格条件和信号逻辑。把alerts_config.json纳入版本管理,每次调整策略时提交一次变更。这样当策略表现异常时,你可以回溯到某个历史版本的配置,对比警报条件的变化。
我自己的习惯是:配置文件按日期分目录存放,比如configs/2025-06-01/alerts_config.json,同时在根目录放一个current.json软链接指向最新版本。脚本默认读current.json,需要回滚时改一下软链接就行。这个习惯帮我省过好几次「后悔药」——有一次策略参数改错了,靠对比前一天的配置快速定位到了问题。
5.5 监控警报触发频率,发现异常信号
警报触发后,3Commas 会执行对应的交易动作。如果某个警报在短时间内频繁触发,可能意味着价格条件设得太靠近当前价,或者市场波动异常。可以在 3Commas 侧设置一个简单的频率监控,当某个币对的信号在 10 分钟内超过 3 次时,发一条通知给自己。
这个监控不需要很复杂,用 3Commas 的日志功能加一个简单的计数脚本就能实现。关键是养成习惯:批量创建的警报不是建完就完了,触发行为本身也是需要观察的信号。希望帮到你。
本文还有配套的精品资源,点击获取