Skill: jiuwei2/tradealpha-open-platformv2 (version 0.0.2)

--- name: tradealpha-open-platformv2 description: Fetch realtime TradeAlpha news across Reuters, Bloomberg, Truth Social, research alerts, and domestic news sources via `POST /api/v1/news/realtime_news`. Use when the user asks to pull TradeAlpha news, realtime news, Reuters news, Bloomberg news, Truth news, domestic headlines, or to filter news by source, category, level, or time range. version: 0.0.2 homepage: https://quantaccess.lxaa.top/ metadata: { "openclaw": { "emoji": "📰", "requires": { "bins": ["node"] }, "primaryEnv": "TradeAlphaToken" }, } --- # TradeAlpha Realtime News 在用户明确表示“帮我拽 TradeAlpha 新闻”“帮我拉取实时新闻”或提到 TradeAlpha 新闻筛选需求时，优先使用本 skill。 本 skill 是可执行版本，默认通过本目录下的脚本完成新闻拉取： - `scripts/get-realtime-news.js` ## Trigger Rules 以下表达默认视为触发词： - 帮我拽 TradeAlpha 新闻 - 帮我拉 TradeAlpha 新闻 - TradeAlpha 实时新闻 - 拉取路透新闻 - 拉取彭博新闻 - 拉取 Truth 新闻 - 拉取国内新闻 - 按来源、分类、重要程度筛选新闻 ## Endpoint - 基础地址：`https://quantaccess.lxaa.top` - 方法：`POST` - 路径：`/api/v1/news/realtime_news` - 完整地址：`https://quantaccess.lxaa.top/api/v1/news/realtime_news` ## Security Disclosure 执行前必须明确下面这些行为： - 新闻请求会发送到 `https://quantaccess.lxaa.top` - 脚本只读取系统环境变量 `TradeAlphaToken` - 如果没有 `TradeAlphaToken`，必须直接报错，并提示用户去 `https://quantaccess.lxaa.top/#/login` 注册、登录、获取 token 后再设置环境变量 - 不要在回复中回显用户 token 如果用户关心安全性，应直接说明以上行为。 ## Workflow 1. 判断用户是否要“TradeAlpha 新闻”或相关筛选新闻。 2. 根据用户自然语言补齐请求参数。 3. 先运行新闻脚本： - `node scripts/get-realtime-news.js '{"source":"bloomberg"}'` 4. 如果脚本返回 `success: true`，整理 `list` 返回给用户。 5. 如果脚本提示缺少 `TradeAlphaToken`，直接告诉用户去 `https://quantaccess.lxaa.top/#/login` 注册、登录、获取 token，并把它设置到系统环境变量 `TradeAlphaToken` 后再试。 6. 如果脚本返回接口错误码，按错误码含义明确告诉用户失败原因。 7. 如果当前运行环境根本没有 shell / exec 能力，立即停止，不要重试，直接告诉用户：当前会话无法执行本地脚本，因此现在不能代为拉取新闻。 ## Execution Rules - 优先运行 `scripts/get-realtime-news.js` - 不要再次读取当前 skill 文件，不要为了执行去查找 `SKILL.md` 路径 - 不要调用 `read`、`sessions_send`、`taskflow` 或类似“先开子任务再执行”的流程 - 不要反复自言自语地宣布“马上执行”或“先读技能文档” - 不要跳过脚本直接编造接口返回 - 不要要求用户自己拼请求体，优先根据自然语言帮用户补参数 - 需要命令示例时，使用本 skill 目录下的脚本路径 - 运行脚本时优先传 JSON 参数对象，不要拆成多组零散命令参数 - 不要再走账号密码登录流程 - 缺少 `TradeAlphaToken` 时，直接停止并给出注册网址说明 - 如果当前会话缺少执行脚本的工具能力，只回复一次明确失败原因，不要循环重试 ## Parameter Mapping - 用户说“今天新闻”“今日新闻”“当天新闻”：优先传当天的 `start_time` 和当前时刻的 `end_time` - 用户未提供时间范围：默认按接口近 24 小时逻辑处理 - 用户说“路透”：`source: "rtrs"` - 用户说“彭博”：`source: "bloomberg"` - 用户说“Truth” 或 “川普 Truth”：`source: "truth"` - 用户说“国内”：`source: "domestic"` - 用户说“研报”：`source: "research_report"` - 用户说“很重要”“重要”“一般”：映射到 `level` - 用户提到分类时，直接使用接口要求的中文全称：`政治军事`、`社会`、`娱乐体育`、`公司`、`超大型公司`、`政策`、`市场与货币` - 用户未指定分页时，默认 `page: 1`、`page_size: 20` - 若用户要求更多结果，可提高 `page_size`，但不得超过 `100` ## Guardrails - `start_time` 和 `end_time` 不能早于北京时间 `2025-04-01` - 若用户显式给出的时间早于下界，应先提醒该限制，不要伪造成功请求 - 单次请求 `page_size` 最大为 `100` - 接口存在客观延迟，新闻通常会晚 `0-5` 分钟 - 不要编造新闻内容、来源、时间或状态码 - 如果接口返回成功，按文档理解 `data.list[]` 只读取 `id`、`datetime`、`content`、`source`、`category`、`level` ## Error Handling - `1001`：token 无效或已过期 - `1002`：请求参数错误 - `1003`：超出请求频率限制 - `1004`：账户余额不足或无权限访问该接口 - `5000`：服务器内部错误 遇到错误时，直接说明原因，并在适合时提示用户检查 token、时间范围、分页大小或频率限制。 ## Response Style - 先给简明摘要，再列出关键新闻 - 保留原始新闻中的时间和来源 - 当结果很多时，优先展示最相关或最新的几条，并说明还有更多结果 - 输出风格保持直接，不要把回复写成接口文档 - 如果因能力限制无法执行，就直接说明“当前会话没有本地脚本执行能力”，不要输出内部思考过程 ## Script Usage ```bash node scripts/get-realtime-news.js node scripts/get-realtime-news.js '{"source":"bloomberg","level":"重要","page_size":5}' ``` ## Additional Resources - 详细参数和错误码见 [reference.md](reference.md) - 请求体和响应示例见 [examples.md](examples.md)

path: examples.md
content: # 请求与响应示例

## 示例请求体

```json
{
  "page": 1,
  "level": "重要",
  "end_time": "2026-04-25 23:00:00",
  "source": "bloomberg",
  "page_size": 100,
  "category": "市场与货币",
  "token": "your token"
}
```

说明：

- `page_size` 在协议上为数字类型；部分客户端以字符串传递时，服务端会按可解析的整数处理。
- 实际执行脚本时，`token` 由系统环境变量 `TradeAlphaToken` 提供；如果没有该环境变量，脚本会直接报错并提示前往 `https://quantaccess.lxaa.top/#/login` 获取 token。

## 示例响应体

```json
{
  "code": 0,
  "message": "success",
  "data": {
    "total": 191,
    "page": 1,
    "page_size": 100,
    "list": [
      {
        "id": 516472,
        "datetime": "2026-04-25 15:00:20",
        "content": "【Out-of-Court Creditor Deals Are Coming to the K-Shaped Debt Market - Bloomberg】\n\n【经济学家长期描述美国经济为K形——富人更富，穷人更穷。同样动态在公司中上演：强公司继续增长并获得资本，弱公司在债务和需求疲软下进一步落后。2028年债务到期墙将至；若高利率持续，偿还贷款人将付出高昂代价，因此许多公司转向负债管理练习（LMEs）。越来越多的公司谈判庭外交易，重新安排还款优先级、延长到期日并说服贷款人提供新资金注入，以保留资金并保持选择开放。Davis Polk & Wardwell重组联席主管Damian Schaible表示：“面临2028/2029到期债务的公司市场有点K形，似乎分为容易再融资和较难的情况。”彭博汇编数据显示，2024年全球LMEs近50个，去年降至少于35个，但这些交易回升；第一季度完成7个，可能很快开始9个。消息人士称，Medical Solutions（Centerbridge和Caisse de Depot et Placement du Quebec所有的高杠杆医疗人员公司）寻求更广泛贷款人支持新资金投资，包括低于面值的债务交换和到期延长。其他消息人士称，Vivid Seats在表现疲软下寻求新资金；债务进入困境后，票务转售商转移抵押品以解锁新融资。彭博早前报道，Cabinetworks（Platinum Equity所有）要求更多债权人进入保密谈判支持债务交易，提供新资本、困境交换和到期延长。Schaible表示，虽然到期墙还有一年多，赞助商和公司可能认为现在是接触债权人的合适时机。“随着到期临近，松散文件价值减少；如果需要与贷款人谈判延期，最好尽早行动。”他预计活动集中在软件、医疗保健和建筑产品等挑战行业。近期交易显示条款如何被重塑：L Catterton支持的RealTruck Group获得3.71亿美元贷款，新设施位于还款线顶端且按比例；交易延长到期并允许交换。同时，无担保债券持有人可以以高折扣切换到更高级债务。Perforce Software（Clearlake Capital和Francisco Partners支持）达成更不寻常交易，允许初级债权人升级到与第一留置权贷款人平等。穆迪评级在4月10日报告中称：“延长到期提供流动性提升，并给予公司额外时间执行AI产品战略。”】\n\nhttps://www.bloomberg.com/news/newsletters/2026-04-25/out-of-court-creditor-deals-are-set-to-hit-the-k-shaped-debt-market",
        "source": "bloomberg",
        "category": "市场与货币",
        "level": "重要"
      }
    ]
  }
}
```

## 常见自然语言映射

- “帮我拽 TradeAlpha 新闻” -> 视为默认新闻请求，脚本会从环境变量 `TradeAlphaToken` 读取 token
- “帮我拉今天的彭博新闻” -> `source: "bloomberg"`，时间范围按当天处理
- “帮我拉路透里很重要的市场与货币新闻” -> `source: "rtrs"`，`level: "很重要"`，`category: "市场与货币"`
- “帮我看近 24 小时国内新闻” -> `source: "domestic"`，时间范围可走接口默认值


path: reference.md
content: # TradeAlpha 实时新闻接口参考

适合投喂 AI：可将本页链接或正文直接提供给 AI，用于快速生成接入代码、请求示例与参数处理逻辑。

## 接口说明

1. 提供国内外新闻实时数据，来源包括但不限于：路透社（含终端）（华区与国际 Top）、彭博社（交易时间终端）（华区与国际 Top）、川普 Truth 平台发言、研报快讯、以及国内主流消息源等。
2. 受采集与传输链路影响，所有消息通常存在约 `0-5` 分钟的延迟；该延迟为客观限制，无法通过技术手段完全消除，接入方请按此预期设计展示或产品说明。
3. 支持按新闻源、重要程度、新闻分类等条件筛选，并可结合请求中的时间范围等参数。

## 请求

### HTTP 方法

```text
POST /api/v1/news/realtime_news
```

### 请求体参数

- `token`：`string`，必填。API 访问令牌，从开放平台申请获得。
- `start_time`：`string`，可选。可只传日期 `YYYY-MM-DD`；若需指定到时刻，须为 `YYYY-MM-DD HH:mm:ss`。
- `end_time`：`string`，可选。可只传日期 `YYYY-MM-DD`；若需指定到时刻，须为 `YYYY-MM-DD HH:mm:ss`。
- `source`：`string`，可选。可选值：
  - `domestic`：国内，库内为 `ths` / `sina`
  - `truth`：川普 Truth
  - `bloomberg`：彭博
  - `rtrs`：路透社
  - `research_report`：研报快讯
- `category`：`string`，可选。传中文全称：
  - `政治军事`
  - `社会`
  - `娱乐体育`
  - `公司`
  - `超大型公司`
  - `政策`
  - `市场与货币`
- `level`：`string`，可选。重要程度：`很重要`、`重要`、`一般`
- `page`：`integer`，可选。页码，默认 `1`
- `page_size`：`integer`，可选。每页条数，默认 `20`，最大 `100`

## 注意事项

- `start_time` 与 `end_time` 均为可选参数，若不传则默认时间范围为近 24 小时。
- 时间下界：新闻时间不能早于 `2025-04-01`（北京时间）。
- 若显式传入的 `start_time` 或 `end_time` 落在该时间之前，将返回 `code: 1002`。
- 未传 `start_time` 时，按默认规则算出的开始时间若早于该下界，将自动从 `2025-04-01`（北京时间）起算。
- 单次请求 `page_size` 上限为 `100`，如需获取更多数据请配合 `page` 参数分页拉取。
- 接口请求频率限制为每分钟不超过 `50` 次；超出限制将返回 `code: 1003`。

## 响应

### 响应字段

- `code`：状态码，`0` 表示成功
- `message`：状态描述
- `data.total`：符合条件的新闻总条数
- `data.page`：当前页码
- `data.page_size`：每页条数
- `data.list`：新闻列表
- `data.list[].id`：新闻唯一 ID
- `data.list[].datetime`：新闻发生时间，格式 `YYYY-MM-DD HH:mm:ss`
- `data.list[].content`：新闻正文内容
- `data.list[].source`：单条新闻的展示用来源
- `data.list[].category`：新闻分类
- `data.list[].level`：重要程度

成功响应中，`data.list[]` 不包含 `import_content` 字段。

## 错误码

- `0`：成功
- `1001`：token 无效或已过期
- `1002`：请求参数错误
- `1003`：超出请求频率限制
- `1004`：账户余额不足或无权限访问该接口
- `5000`：服务器内部错误

## 页面链接

- [TradeAlpha Open Platform](https://quantaccess.lxaa.top/)


path: scripts/get-realtime-news.js
content: const REALTIME_NEWS_URL =
  "https://quantaccess.lxaa.top/api/v1/news/realtime_news";
const TOKEN_ENV_NAME = "TradeAlphaToken";
const TOKEN_GUIDE_URL = "https://quantaccess.lxaa.top/#/login";

const MIN_NEWS_TIME = "2025-04-01 00:00:00";
const DATE_ONLY_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
const DATE_TIME_PATTERN = /^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/;
const NEWS_SOURCES = [
  "domestic",
  "truth",
  "bloomberg",
  "rtrs",
  "research_report",
];
const NEWS_CATEGORIES = [
  "政治军事",
  "社会",
  "娱乐体育",
  "公司",
  "超大型公司",
  "政策",
  "市场与货币",
];
const NEWS_LEVELS = ["很重要", "重要", "一般"];

function printHelp() {
  console.log("TradeAlpha 实时新闻脚本");
  console.log("");
  console.log("用法:");
  console.log("  node scripts/get-realtime-news.js");
  console.log(
    '  node scripts/get-realtime-news.js \'{"source":"bloomberg","level":"重要","page_size":5}\'',
  );
  console.log("");
  console.log("支持字段:");
  console.log("  start_time, end_time, source, category, level, page, page_size");
}

function printJson(payload, error = false) {
  const encoded = JSON.stringify(payload, null, 2);
  if (error) {
    console.error(encoded);
    return;
  }

  console.log(encoded);
}

function readStoredToken() {
  const envToken = process.env[TOKEN_ENV_NAME]?.trim();
  if (envToken) {
    return {
      [REDACTED_SECRET],
      token_source: "env",
    };
  }

  return {
    token: null,
    token_source: "none",
  };
}

function parseInput(argv) {
  const firstArg = argv[0];
  if (!firstArg) {
    return {};
  }

  if (firstArg === "--help" || firstArg === "-h") {
    printHelp();
    process.exit(0);
  }

  try {
    const parsed = JSON.parse(firstArg);
    if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
      throw new Error("输入必须是 JSON 对象。");
    }
    return parsed;
  } catch (error) {
    throw new Error(
      `参数必须是单个 JSON 对象字符串，例如 '{"source":"bloomberg","page_size":5}'。原始错误：${
        error instanceof Error ? error.message : String(error)
      }`,
    );
  }
}

function parseOptionalString(args, key) {
  const value = args[key];
  if (value == null) {
    return undefined;
  }

  if (typeof value !== "string") {
    throw new Error(`参数 \`${key}\` 必须是字符串。`);
  }

  const trimmed = value.trim();
  return trimmed || undefined;
}

function parseOptionalInteger(args, key) {
  const value = args[key];
  if (value == null) {
    return undefined;
  }

  if (typeof value === "number" && Number.isInteger(value)) {
    return value;
  }

  if (typeof value === "string" && value.trim() !== "") {
    const parsed = Number(value);
    if (Number.isInteger(parsed)) {
      return parsed;
    }
  }

  throw new Error(`参数 \`${key}\` 必须是整数。`);
}

function validateEnum(value, key, allowedValues) {
  if (!value) {
    return undefined;
  }

  if (!allowedValues.includes(value)) {
    throw new Error(
      `参数 \`${key}\` 取值无效，可选值为：${allowedValues.join("、")}。`,
    );
  }

  return value;
}

function normalizeComparableTime(value) {
  return DATE_ONLY_PATTERN.test(value) ? `${value} 00:00:00` : value;
}

function validateTimeFormat(value, key) {
  if (!DATE_ONLY_PATTERN.test(value) && !DATE_TIME_PATTERN.test(value)) {
    throw new Error(
      `参数 \`${key}\` 格式无效，必须为 YYYY-MM-DD 或 YYYY-MM-DD HH:mm:ss。`,
    );
  }

  if (normalizeComparableTime(value) < MIN_NEWS_TIME) {
    throw new Error(
      `参数 \`${key}\` 不能早于 2025-04-01 00:00:00（北京时间）。`,
    );
  }
}

function buildRequest(rawArgs) {
  const start_time = parseOptionalString(rawArgs, "start_time");
  const end_time = parseOptionalString(rawArgs, "end_time");
  const source = validateEnum(
    parseOptionalString(rawArgs, "source"),
    "source",
    NEWS_SOURCES,
  );
  const category = validateEnum(
    parseOptionalString(rawArgs, "category"),
    "category",
    NEWS_CATEGORIES,
  );
  const level = validateEnum(
    parseOptionalString(rawArgs, "level"),
    "level",
    NEWS_LEVELS,
  );
  const page = parseOptionalInteger(rawArgs, "page") ?? 1;
  const page_size = parseOptionalInteger(rawArgs, "page_size") ?? 20;

  if (start_time) {
    validateTimeFormat(start_time, "start_time");
  }
  if (end_time) {
    validateTimeFormat(end_time, "end_time");
  }
  if (
    start_time &&
    end_time &&
    normalizeComparableTime(start_time) > normalizeComparableTime(end_time)
  ) {
    throw new Error("`start_time` 不能晚于 `end_time`。");
  }
  if (page < 1) {
    throw new Error("参数 `page` 必须大于或等于 1。");
  }
  if (page_size < 1 || page_size > 100) {
    throw new Error("参数 `page_size` 必须在 1 到 100 之间。");
  }

  return {
    start_time,
    end_time,
    source,
    category,
    level,
    page,
    page_size,
  };
}

async function fetchRealtimeNews(request, token) {
  const response = await fetch(REALTIME_NEWS_URL, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      Authorization: `Bearer ${token}`,
    },
    body: JSON.stringify({
      ...request,
      token,
    }),
  });

  let payload;
  try {
    payload = await response.json();
  } catch {
    throw new Error(`新闻接口返回了非 JSON 响应，HTTP ${response.status}。`);
  }

  if (!response.ok || payload?.code !== 0 || !payload?.data) {
    const detail =
      typeof payload?.message === "string"
        ? payload.message
        : `HTTP ${response.status}`;
    const codeText =
      typeof payload?.code === "number" ? `（code: ${payload.code}）` : "";
    const error = new Error(`获取新闻失败${codeText}：${detail}`);
    error.tradealpha_code =
      typeof payload?.code === "number" ? payload.code : null;
    throw error;
  }

  return payload.data;
}

async function main() {
  const args = parseInput(process.argv.slice(2));
  const request = buildRequest(args);
  const auth = readStoredToken();

  if (!auth.token) {
    printJson(
      {
        success: false,
        auth_required: false,
        next_action: "set_env",
        token_source: auth.token_source,
        error: `未找到环境变量 \`${TOKEN_ENV_NAME}\`。请先前往 ${TOKEN_GUIDE_URL} 注册并登录，获取 token 后将其设置到系统环境变量 \`${TOKEN_ENV_NAME}\` 中。`,
        message: `当前还没有可用 token，请先设置环境变量 \`${TOKEN_ENV_NAME}\`。`,
        guide_url: TOKEN_GUIDE_URL,
      },
      true,
    );
    process.exitCode = 1;
    return;
  }

  const data = await fetchRealtimeNews(request, auth.token);
  printJson({
    success: true,
    auth_required: false,
    next_action: "none",
    token_source: auth.token_source,
    request,
    total: data.total,
    page: data.page,
    page_size: data.page_size,
    list: data.list,
    note: "新闻数据通常存在 0-5 分钟客观延迟。",
  });
}

main().catch((error) => {
  const message = error instanceof Error ? error.message : String(error);
  const tradealphaCode =
    typeof error?.tradealpha_code === "number" ? error.tradealpha_code : null;
  const tokenInvalid = tradealphaCode === 1001;

  printJson(
    {
      success: false,
      auth_required: false,
      next_action: tokenInvalid ? "set_env" : "fetch_news",
      token_source: "none",
      error: message,
      error_code: tradealphaCode,
      message: tokenInvalid
        ? `环境变量 \`${TOKEN_ENV_NAME}\` 中的 token 无效或已过期，请前往 ${TOKEN_GUIDE_URL} 重新获取后更新环境变量。`
        : "新闻拉取失败，请检查参数或稍后重试。",
      guide_url: tokenInvalid ? TOKEN_GUIDE_URL : undefined,
    },
    true,
  );
  process.exitCode = 1;
});


Security scan verdicts — ClawScan: suspicious | static analysis: suspicious | VirusTotal: clean | SkillSpector: suspicious (HIGH)