AI 量化交易系统AI 量化交易系统
首页
系统架构
  • PC 端获取
  • 手机端获取
TV 指标字段
数据源订阅
  • 1. 数据源配置
  • 2. 聚合平台部署
  • 3. 大模型接入
  • 4. 桌面客户端中继安装
  • 5. 交易所接入配置
  • 6. MT5 对接教程
  • 7. 通达信对接教程
  • 8. MiniQMT 对接教程
  • 9. 风控规则设置
  • data-feeder (GitHub)
  • data-feeder (Gitee)
首页
系统架构
  • PC 端获取
  • 手机端获取
TV 指标字段
数据源订阅
  • 1. 数据源配置
  • 2. 聚合平台部署
  • 3. 大模型接入
  • 4. 桌面客户端中继安装
  • 5. 交易所接入配置
  • 6. MT5 对接教程
  • 7. 通达信对接教程
  • 8. MiniQMT 对接教程
  • 9. 风控规则设置
  • data-feeder (GitHub)
  • data-feeder (Gitee)
  • 系统架构
  • 获取 API Key

    • 获取 API Key — PC 端
    • 获取 API Key — 手机端
  • TV 指标字段
  • 数据源订阅
  • 系列教程

    • 数据源配置指南
    • /guide/aggregation-platform.html
    • /guide/llm-setup.html
    • 桌面客户端中继安装
    • 数字货币对接教程
    • MT5 对接教程
    • 通达信对接教程
    • MiniQMT 对接教程
    • /guide/risk-control.html

数据源配置指南

这是 AI 量化交易系统系列教程的第一篇。数据源是整个系统的"眼睛和耳朵"——所有后续的 AI 分析和交易决策都建立在这些数据之上。

本篇基于开源项目 data-feeder(GitHub / Gitee),讲清楚一件事:如何通过 TradingView WebSocket 直连,在 K 线收盘的瞬间采集 13 个时间级别的指标趋势线数据,零延迟回写到服务端。


获取项目

项目已同步发布到 GitHub 和 Gitee,按网络情况任选其一。以下按截图步骤引导你完成下载。

方式一:Gitee(国内推荐,速度快)

第 1 步:打开 Gitee 仓库页面,点击橙色的「克隆/下载」按钮:

Gitee 仓库页面 — 点击克隆/下载

第 2 步:在弹出的对话框中,你可以选择两种方式:

Gitee 克隆/下载弹窗 — 复制地址或下载 ZIP

  • 下载 ZIP(图中红箭头):直接下载压缩包,解压即可使用,适合不熟悉 Git 的用户
  • 复制 git clone 命令:在终端中粘贴执行,适合需要后续 git pull 更新的用户
# 终端执行(Gitee)
git clone https://gitee.com/xibusuper/data-feeder.git
cd data-feeder

方式二:GitHub(海外网络)

打开 GitHub 仓库页面,点击绿色的「Code」按钮,在下拉菜单底部点击「Download ZIP」:

GitHub 仓库页面 — Code 菜单下载 ZIP

也可以复制 HTTPS 地址用终端克隆:

# 终端执行(GitHub)
git clone https://github.com/xibusuper/data-feeder.git
cd data-feeder

后续更新

如果通过 git clone 方式获取的项目,后续更新只需一条命令:

git pull

下载 ZIP 的用户需要重新下载新版本覆盖旧文件。


项目结构

data_client/
├── clients/
│   └── tv-indicator.js     # TradingView 指标采集(多周期共振 v2.0)— 命令行入口
├── lib/
│   └── OpenApiClient.js    # 开放平台 API 封装类(fetchTvData/writeTvDataList/reportStatus/fetchLastDataList/fetchDataList)
├── package.json
├── .env.example            # 配置文件模板(复制为 .env 使用)
├── .gitignore
├── Dockerfile              # Docker 镜像构建(多阶段,非 root 运行)
├── docker-compose.yml      # Docker Compose 一键编排
├── .dockerignore
└── README.md

整个项目核心源码文件:clients/tv-indicator.js 是主程序,lib/OpenApiClient.js 是 API 封装类。依赖也只有两个:@mathieuc/tradingview(TradingView API 库,来自 GitHub)和 dotenv(配置读取)。


环境准备

安装 Git

如果本机尚未安装 Git,请前往 git-scm.com 下载对应操作系统的安装包。

安装完成后验证:

git --version    # 确认 git 可用

安装 Node.js >= 18

项目使用 Node.js 内置的 fetch API(18.0.0 起内置),不再需要 axios 等第三方 HTTP 库。前往 nodejs.org 下载 LTS 版本,安装后验证:

node --version   # 应输出 v18.x.x 或更高

Windows Server 2012 用户

Server 2012 不支持新版 Node.js 安装包,请下载 Node.js 18 专用版本:node-v18.20.8-x64.msi

后端服务

采集客户端需要连接后端服务(默认地址 https://traderai.vip)。后端需提前创建好以下数据:

数据表说明关键字段
bot_tv_userTV 用户配置session_id、session_sign、indicator_id(获取方式见 TV 指标字段)
bot_tv_data数据源订阅关联 TV 用户或交易所账号,配置交易所/币种/周期/K线类型
bot_api_key访问密钥用于开放接口 Bearer Token 鉴权(获取方式见 PC 端获取 / 手机端获取)

配置

复制配置模板并填写实际值:

cp .env.example .env

编辑 .env:

# 开放接口地址(后端服务地址)
# 默认写死为正式服务器:https://traderai.vip
# Docker 运行时若后端在宿主机,可填 http://host.docker.internal:7000 覆盖
API_URL=https://traderai.vip

# 访问密钥(bot_api_key 表中的 api_key)
# 也可通过命令行 -k 传入,命令行优先级更高
API_KEY=

# 数据源ID(bot_tv_data 表的自增 id)
# 该 ID 对应的数据源可关联 TV 用户(target_type=1)或交易所账号(target_type=2)
# 也可通过命令行 -i 传入,命令行优先级更高
TV_DATA_ID=

# 价格保留小数位数(默认 2)
PRICE_PRECISION=2

API_KEY 和 TV_DATA_ID 是必填项。两个都没有的情况下程序启动即报错退出:

[错误] 缺少 api_key,请通过 -k/--api-key 传入或在 .env 中配置 API_KEY
[错误] 缺少数据源 id,请通过 -i/--tv-data-id 传入或在 .env 中配置 TV_DATA_ID

命令行参数优先级高于 .env,方便临时切换数据源而不修改配置文件。

参数速查

来源参数说明必填默认值
.envAPI_URL开放接口地址否https://traderai.vip
.env / -kAPI_KEY访问密钥是—
.env / -iTV_DATA_ID数据源 ID是—
.env / -pPRICE_PRECISION价格小数位数否2
—-d调试模式否关闭

运行方式一:本地运行

安装依赖

进入项目目录后安装依赖:

cd data-feeder
npm install

启动采集

# 方式一:全部从 .env 读取
node clients/tv-indicator.js

# 方式二:命令行传参(覆盖 .env)
node clients/tv-indicator.js -k 你的API_Key -i 数据源ID

# 开启调试模式
node clients/tv-indicator.js -k 你的API_Key -i 数据源ID -d

参数说明

参数说明获取方式
-kAPI Key(访问密钥)参考 PC 端获取 或 手机端获取 教程,点击「复制」按钮获取完整 Key
-i数据源 ID聚合 SaaS 系统 → 数据源订阅页面中的 ID 列数字(见下方截图)
-d调试模式无需传值,加上即开启

⚠️ 数据源 ID 必须是自己创建的

-i 后面的数字对应你在聚合 SaaS 系统中自己创建的数据源订阅记录的 ID。不能使用别人的数据源 ID,否则会因权限不足导致采集失败。

数据源 ID 在哪里找?

登录聚合 SaaS 系统后台,在左侧导航栏点击「业务管理」→「数据源订阅」,列表中第一列的 ID 就是对应的数字:

数据源订阅页面 — ID 列即为 -i 参数值

启动后你会看到类似输出:

data-feeder 运行成功示例

运行成功的标志:

  1. 「客户端连接成功!」 — WebSocket 已连接 TradingView
  2. 「指标准备就绪!」 — 指标加载成功,开始接收数据
  3. 「等待5分钟K线收盘...」 — 正常等待中,K 线收盘时会自动采集
  4. 趋势线数据表格 — 13 个时间级别的趋势线值、与价格差值、多空方向
  5. 「[写入成功]」 — 数据已成功写入服务端数据库

数据上报成功后,回到聚合 SaaS 系统后台,点击数据源订阅页面中的**「运行记录」**,即可查看上报的指标数据。

查看帮助

node clients/tv-indicator.js -h

退出

按 Ctrl + C,客户端清理 WebSocket 连接后退出。


运行方式二:Docker 运行

生产环境推荐使用 Docker,自动重启、隔离环境、方便部署。

Docker Compose 一键启动

# 1. 配置好 .env(填写 API_KEY / TV_DATA_ID)
# 2. 构建并后台启动
docker compose up -d --build

# 3. 查看实时日志
docker compose logs -f

# 4. 停止
docker compose down

# 5. 更新代码后重新构建
git pull && docker compose up -d --build

docker 命令直接运行

docker build -t tradingbot-data-client:latest .

docker run -d \
  --name tradingbot-data-client \
  --restart unless-stopped \
  --add-host host.docker.internal:host-gateway \
  -e API_URL=https://traderai.vip \
  -e API_KEY=your_api_key \
  -e TV_DATA_ID=1 \
  -e PRICE_PRECISION=2 \
  tradingbot-data-client:latest

Docker 网络说明

后端位置API_URL 取值
正式服务器(默认)https://traderai.vip
宿主机本地http://host.docker.internal:7000(Linux 需加 --add-host)
同一 Docker 网络http://<后端服务名>:7000
公网/远程直接填公网地址

核心原理:毫秒级指标采集

这是整个项目最有创新性的部分。传统的数据采集方式是定时轮询——每隔 1 分钟发一次 HTTP 请求拉数据。这种方式有两个问题:延迟高(最慢差一个轮询周期),且在 K 线还没收盘时拿到的是不完整的中间值。

data-feeder 采用了完全不同的思路:WebSocket 直连 + 时间戳变化检测,在 K 线收盘的瞬间触发采集,延迟控制在毫秒级。

第一步:WebSocket 直连 TradingView

程序启动后,通过 OpenApiClient 从服务端获取订阅配置(交易所、币种、周期、TV 凭证),然后建立 WebSocket 连接:

// 从服务端获取配置
const { tv_data, tv_user } = await openApi.fetchTvData(tvDataId);

// 用 TV 凭证创建 WebSocket 客户端
const client = new TradingView.Client({
  token: tv_user.tv_session_id,
  signature: tv_user.tv_session_sign,
});

// 创建图表会话,设置交易对和周期
const chart = new client.Session.Chart();
chart.setMarket(`${exchange}:${symbol}`, {
  timeframe: String(timeframe),
  range: 20,
  type: chartType === 'heikin' ? 'HeikinAshi' : undefined,
});

WebSocket 连接建立后,TradingView 会持续推送实时数据,不需要客户端反复请求。

第二步:加载指标并激活隐藏时间级别

获取指标实例后,程序会打开默认关闭的时间级别开关。这一步是关键——TradingView 的某些指标默认只显示部分时间级别,需要手动激活:

const indicator = await TradingView.getIndicator(indicatorScriptId, 'last', sessionId);

// 打开默认关闭的时间级别
indicator.setOption('in_55', true);  // h8  (8小时)
indicator.setOption('in_63', true);  // h12 (12小时)
indicator.setOption('in_71', true);  // d1  (1日)

// 创建 Study 实例挂载到图表
const study = new chart.Study(indicator);

参数名 in_55、in_63、in_71 对应指标内部定义的输入参数 key。每个时间级别的第一组参数中,type="bool" 的即为显示开关。用 -d 调试模式可以看到所有可用参数。

第三步:K 线收盘检测

这是毫秒级采集的核心。程序通过比较相邻两次 onUpdate 回调中的 K 线时间戳来判断收盘:

let previousTime = null;

study.onUpdate(() => {
  if (!study.periods || study.periods.length === 0) return;

  const currentPeriod = study.periods[0];
  const currentTime = currentPeriod.$time;

  // 时间戳变化 = 新K线开始 = 上一根已收盘
  if (previousTime !== null && previousTime !== currentTime) {
    // periods[1] 就是刚收盘那根K线的最终数据
    const closedPeriod = study.periods[1];
    if (closedPeriod) {
      handleKlineClose(closedPeriod, currentPrice);
    }
  }

  previousTime = currentTime;
});

study.periods 数组按时间倒序排列:[0] 是当前正在形成的 K 线,[1] 是上一根已收盘的 K 线。当 periods[0].$time 发生变化时,意味着新 K 线开始了——上一根已经收盘,periods[1] 中的数据就是最终值。

从 K 线收盘到数据采集完成,整个过程在同一个 WebSocket 回调中同步执行,没有 HTTP 轮询的等待间隔,延迟控制在毫秒级。

第四步:提取 13 个时间级别的趋势线数据

一根 K 线收盘后,程序从 period 对象中提取 13 个时间级别的趋势线数值:

const TIMEFRAMES = ['cur', 'm10', 'm15', 'm30', 'h1', 'h2', 'h4', 'h8', 'h12', 'd1', 'd2', 'd3', 'd5'];

function extractTrendData(period, precision, price) {
  const NO_DATA = 1e+100;  // TradingView 无趋势哨兵值
  const trendData = {};

  TIMEFRAMES.forEach((tf) => {
    const val = period[tf];
    if (val !== undefined && val !== null && val !== NO_DATA) {
      const formattedVal = Number(val.toFixed(precision));
      if (price > 0) {
        // value < price → 做多方向 → _duo
        // value >= price → 做空方向 → _kong
        const suffix = val < price ? '_duo' : '_kong';
        trendData[`${tf}${suffix}`] = formattedVal;
      } else {
        trendData[tf] = formattedVal;
      }
    }
  });

  return trendData;
}

这里有两个细节值得注意:

哨兵值过滤:TradingView 在没有趋势数据时返回 1e+100(一个天文数字),而不是 null 或 undefined。程序会过滤掉这个值,避免把 1e+100 当成真实趋势线价格。

多空方向标记:趋势线值低于当前价格意味着价格在趋势线上方(多头格局),标记为 _duo;反之标记为 _kong。这样 AI 拿到数据后一眼就能看出每个时间级别的多空方向,不需要再做比较计算。

采集的时间级别

字段含义字段含义
cur当前周期h88 小时
m1010 分钟h1212 小时
m1515 分钟d11 天
m3030 分钟d22 天
h11 小时d33 天
h22 小时d55 天
h44 小时

变量名按趋势方向加后缀:_duo(做多)、_kong(做空)。例如 m15_duo: 100.5 表示 15 分钟级别趋势线值 100.5,低于当前价格,多头格局。

第五步:零延迟回写服务端

K 线收盘后,趋势线数据立即通过 OpenApiClient 写入服务端数据库:

async function handleKlineClose(closedPeriod, price) {
  const klineTimeMs = closedPeriod.$time * 1000;  // TV 返回秒级,DB 存毫秒

  const trendData = extractTrendData(closedPeriod, precision, price);

  const payload = {
    tv_data_id: tvDataId,
    data: JSON.stringify(trendData),       // 如 {"m15_duo":100.5,"h1_kong":101.2,...}
    kline_time: klineTimeMs,
    price: price.toFixed(precision),
  };

  await openApi.writeTvDataList(payload);
}

写入失败时只打印错误日志,不影响采集进程继续运行。


OpenApiClient 类

开放平台的五个接口已封装到 lib/OpenApiClient.js,可以在自己的脚本中独立复用:

const { OpenApiClient } = require('./lib/OpenApiClient');

const client = new OpenApiClient({
  apiUrl: 'https://traderai.vip',
  apiKey: 'your_api_key',
});

// 1. 获取数据源订阅配置 + TV 用户凭证
const { tv_data, tv_user } = await client.fetchTvData(1);

// 2. 写入 K 线收盘指标数据
await client.writeTvDataList({
  tv_data_id: 1,
  data: JSON.stringify({ m15_duo: 100.5, h1_kong: 101.2 }),
  kline_time: Date.now(),
  price: '100.80',
});

// 3. 上报运行状态(0=停止, 1=运行中, 2=异常)
await client.reportStatus(1, 1, '');

// 4. 获取最后一条数据记录(无数据时返回空对象)
const last = await client.fetchLastDataList(1);

// 5. 获取最近若干条记录(默认 10 条,最大 100 条,按 id 降序)
const list = await client.fetchDataList(1, 10);

五个接口均需在请求头携带 Authorization: Bearer <api_key>,类内部已自动处理。

接口方法说明封装方法
/api/open/tvData/:idGET获取订阅配置 + TV 凭证fetchTvData()
/api/open/tvDataList/writePOST写入 K 线收盘数据writeTvDataList()
/api/open/tvData/:id/statusPOST上报运行状态reportStatus()
/api/open/tvDataList/lastDataListGET获取最后一条记录fetchLastDataList()
/api/open/tvDataList/listGET获取最近若干条记录(limit 1~100)fetchDataList()

调试模式

加 -d 或 --debug 参数启动时,程序会打印指标加载的原始入参和出参,包括:

  • getIndicator 的 scriptId、sessionId 入参
  • 指标的 shortDescription、description、pineId
  • 所有输入参数定义(inputs)和当前值(options)
  • 所有输出定义(plots)
  • 完整指标对象的 JSON 序列化
node clients/tv-indicator.js -k abc123def456 -i 1 -d

调试输出示例:

--- [调试] getIndicator 入参 ---
  scriptId : USER;YourIndicator
  version  : last
  sessionId: eyJ...

--- [调试] getIndicator 出参(指标元信息)---
  shortDescription: MyTrendIndicator
  description     : Multi-timeframe trend lines

  === 指标输入参数定义 (inputs) ===
  [in_55]: {"name":"显示","type":"bool",...}    # h8 开关
  [in_63]: {"name":"显示","type":"bool",...}    # h12 开关
  [in_71]: {"name":"显示","type":"bool",...}    # d1 开关

  === 指标输出定义 (plots) ===
  [0] id=0 type=Line target=cur
  [1] id=1 type=Line target=m10
  ...
--- [调试] 结束 ---

如果需要修改指标参数(如周期长度、数据源、乘数),在调试输出中找到对应的 in_xx key,然后在代码中添加:

indicator.setOption('in_55', true);   // 已有:激活 h8
// indicator.setOption('Length', 14); // 示例:修改周期长度
// indicator.setOption('Multiplier', 2.0); // 示例:修改乘数

容错机制

采集客户端需要 7×24 小时稳定运行,内置了多层容错:

异常场景处理方式
获取配置失败指数退避重试(5s → 10s → 20s → … 最长 60s)
WebSocket 断连5 秒后自动重新连接
数据写入失败仅打印错误日志,不影响采集进程
30 秒未获取到数据自动重新初始化连接
Docker 异常退出restart: unless-stopped 自动拉起

每次异常发生时,程序都会通过 reportStatus 接口上报状态(2=异常)和错误信息到服务端,方便运维监控。


数据源订阅配置说明

后端管理后台中创建数据源订阅时,需要理解 target_type 字段的含义:

target_type关联目标凭证来源
1TV 用户(bot_tv_user)TV 用户的 session_id、session_sign、indicator_id
2交易所账号交易所账号关联的 TV 凭证

两种类型最终都提供 TV 凭证给采集客户端使用。区别在于凭证的管理入口不同——target_type=1 直接在 TV 用户管理中维护,target_type=2 绑定在交易所账号上。

K 线类型

chart_type 值说明
regular普通K线(默认)
heikin平均K线(Heikin Ashi)

平均K线会平滑价格波动,适合趋势分析。程序通过 chart.setMarket 的 type 参数切换。


测试与验证

验证清单

逐项检查,全部通过后再进入下一篇教程:

检查项验证方法预期结果
Node.js 版本node --versionv18 或更高
git 可用git --version输出版本号
依赖安装npm install无报错
.env 配置cat .envAPI_KEY 和 TV_DATA_ID 已填写
API_KEY 校验node clients/tv-indicator.js(不传 -k)无"缺少 api_key"报错
TV_DATA_ID 校验node clients/tv-indicator.js(不传 -i)无"缺少数据源 id"报错
服务端连通node clients/tv-indicator.js显示"客户端连接成功"
指标加载node clients/tv-indicator.js显示"指标准备就绪"
K 线收盘采集等待一根 K 线收盘控制台输出趋势线数据
数据写入查看服务端数据库bot_tv_data_list 表有新记录
调试模式node clients/tv-indicator.js -d打印指标原始入参/出参
Docker 运行docker compose up -d容器正常运行

快速验证流程

# 1. 克隆项目
git clone https://gitee.com/xibusuper/data-feeder.git
cd data-feeder

# 2. 安装依赖
npm install

# 3. 配置
cp .env.example .env
# 编辑 .env,填入 API_KEY 和 TV_DATA_ID

# 4. 调试模式启动(查看指标加载详情)
node clients/tv-indicator.js -d

# 5. 确认指标加载成功后,Ctrl+C 退出,正常模式启动
node clients/tv-indicator.js

# 6. 等待一根 K 线收盘,观察控制台输出

常见问题

提示"缺少 api_key"

在 .env 中填写 API_KEY=你的密钥,或者运行时加 -k 你的密钥。两个都没有时程序直接退出。

提示"缺少数据源 id"

在 .env 中填写 TV_DATA_ID=数字ID,或者运行时加 -i 数字ID。这个 ID 是后端 bot_tv_data 表的自增主键,需要在管理后台先创建数据源订阅。

WebSocket 连接失败

检查后端返回的 TV 凭证是否有效。session_id 和 session_sign 是 TradingView 的登录 Cookie,有有效期,过期后需要在管理后台更新。获取方式:浏览器打开 tradingview.com 登录 → F12 → Application → Cookies → 复制 sessionid 和 signature。

指标加载失败

确认 indicator_id(指标脚本 ID)正确。私有 Pine Script 指标的 ID 格式通常是 USER;xxxxx,需要指标作者分享给你并且你的 TV 账号有访问权限。用 -d 调试模式查看 getIndicator 的原始入参和报错信息。

某些时间级别没有数据

检查是否已激活隐藏的时间级别开关。代码中已默认激活 in_55(h8)、in_63(h12)、in_71(d1)。如果需要其他级别,用 -d 调试模式查看指标的所有 inputs 定义,找到对应级别的 in_xx key 并在代码中添加 indicator.setOption('in_xx', true)。

TradingView 返回 1e+100

这是 TradingView 表示"无趋势数据"的哨兵值,不是真实价格。程序已自动过滤,不会写入数据库。如果所有级别都返回 1e+100,说明指标还没有计算出趋势线,通常是因为 K 线历史数据不足。

Docker 容器无法连接后端

如果后端运行在宿主机上(非容器),API_URL 需要填 http://host.docker.internal:7000,并且在 Linux 上需要加 --add-host host.docker.internal:host-gateway。Docker Compose 方式已在 docker-compose.yml 中配置好。


扩展:接入其他数据源

data-feeder 专注于 TradingView 指标采集。如果你还需要接入其他数据源(行情 API、新闻数据、自定义数据),可以使用 OpenApiClient 类的 writeTvDataList 方法,遵循相同的数据写入格式:

const { OpenApiClient } = require('./lib/OpenApiClient');

const client = new OpenApiClient({
  apiUrl: process.env.API_URL,
  apiKey: process.env.API_KEY,
});

// 写入自定义数据(如新闻情绪分析结果)
await client.writeTvDataList({
  tv_data_id: customDataSourceId,
  data: JSON.stringify({
    sentiment_score: 0.72,
    news_count: 15,
    top_keywords: ['BTC', 'ETF', '降息'],
  }),
  kline_time: Date.now(),
  price: '0.72',
});

只要数据写入 bot_tv_data_list 表,聚合平台就能统一读取并交给大模型分析。


写在最后

大家可以参考本项目的代码进行修改,适配自己的指标和交易策略。如果实在不知道怎么改,推荐下载字节跳动的专业 AI 编程工具 Trae,用 AI 辅助编程,分分钟就能搞定。

后续我还会分享更多实战例子,全部开源供大家参考。

Next
/guide/aggregation-platform.html