# @backtest-kit/graph 中文文档

规范地址：https://npmcn.com/package/%40backtest-kit/graph/

版本：23\.7\.0
npm 元数据更新时间：2026-10-29T15:11:37.785Z
中文译文更新时间：2026-11-07T21:05:39.563Z
软件包许可：MIT

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40backtest-kit/graph
原文对照：https://npmcn.com/package/%40backtest-kit/graph/?lang=original
项目主页：https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html
源码仓库：https://github.com/tripolskypetr/backtest-kit

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：42.8 kB，5 个文件
- 模块格式：ESM + CJS
- TypeScript 类型：包内自带
- 运行依赖：1 个
- peer 依赖：typescript ^5\.0\.0，backtest-kit ^23\.7\.0
- 首次发布：2026-02-18T19:30:02.625Z
- 最新版本发布：2026-10-29T15:11:37.370Z
- 近 30 天下载量：2554（2026-10-08 至 2026-11-06，npm 官方下载统计）
- 已发布版本数：163（近 12 个月 163 个）

## 中文简介

将反向测试-吻合计算编为被打入的定向循环图. 定义获取市场数据的源节点和计算出衍生值的输出节点——然后按照地理学顺序解决整个图.

## 安装

```sh
npm install @backtest-kit/graph
```

也可以使用：`pnpm add @backtest-kit/graph`、`yarn add @backtest-kit/graph`、`bun add @backtest-kit/graph`

## README

![](https://github.com/tripolskypetr/backtest-kit/raw/refs/heads/master/assets/assignation.svg)

# @ backtest- kit/ graph

> 编曲 [反测试- kit](https://www.npmjs.com/package/backtest-kit) 以打入的定向循环图计算。 声明 **源节点** 获取市场数据和 **输出节点** ——然后按地貌顺序解决整个图,平行地,完全地排入.

![screenshot](https://raw.githubusercontent.com/tripolskypetr/backtest-kit/HEAD/assets/screenshots/screenshot16.png)

[![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/tripolskypetr/backtest-kit) [![npm](https://img.shields.io/npm/v/@backtest-kit/graph.svg?style=flat-square)](https://npmjs.org/package/@backtest-kit/graph) ![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue)

📚 **[文档](https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html)** • 妇女 **[参考执行情况](https://github.com/tripolskypetr/backtest-kit/tree/master/example)** • 妇女 **[GitHub 图像](https://github.com/tripolskypetr/backtest-kit)**

```bash
npm install @backtest-kit/graph backtest-kit
```

* * *

## 是为了什么

一个交易信号很少是一个数字——这是一个小的计算:拉出4h的趋势,拉出15m的输入,结合它们,也许在RSI上的出门. 已写入内线, 成为 `await`手控订单 这个包让你宣布为 **输入节点的图表**: 叶(`sourceNode`获取数据,分支( )`outputNode`从他们的子女中计算 `resolve()` 由下而上地走着树——解决每个节点的依赖性 **平行** (单位:千美元)`Promise.all`在计算节点本身之前。 刷取一个时间段或添加一个过滤节点不需要修改策略线条,而TypeScript通过整个图表推断出数值类型.

它直接插入一个 `getSignal` 并运行在反测试 -kit的 执行背景,所以 `sourceNode`是因为 `fetch` 自动接收 `(symbol, when, currentPrice, exchangeName)` ——引擎其余部分看到的同一种外观安全"现在".

* * *

## 多时间框架松树战略(犬科的例子)

双时间框架战略:a **4h 松树脚本** 充当趋势过滤器, a **15米松脚本** 生成条目。 输出节点结合它们并返回 `null` 只要趋势与条目不一致——所以一个长长的信号在下行和倒行逆施中被压制.

守则

```typescript
import { extract, run, toSignalDto, File } from '@backtest-kit/pinets';
import { addStrategySchema, Cache } from 'backtest-kit';
import { randomString } from 'functools-kit';
import { sourceNode, outputNode, resolve } from '@backtest-kit/graph';

// SourceNode — 4h trend filter, cached per candle interval
const higherTimeframe = sourceNode(Cache.fn(async (symbol) => {
  const plots = await run(File.fromPath('timeframe_4h.pine'), { symbol, timeframe: '4h', limit: 100 });
  return extract(plots, { allowLong: 'AllowLong', allowShort: 'AllowShort', noTrades: 'NoTrades' });
}, { interval: '4h', key: ([symbol]) => symbol }));

// SourceNode — 15m entry signal, cached per candle interval
const lowerTimeframe = sourceNode(Cache.fn(async (symbol) => {
  const plots = await run(File.fromPath('timeframe_15m.pine'), { symbol, timeframe: '15m', limit: 100 });
  return extract(plots, { position: 'Signal', priceOpen: 'Close', priceTakeProfit: 'TakeProfit', priceStopLoss: 'StopLoss', minuteEstimatedTime: 'EstimatedTime' });
}, { interval: '15m', key: ([symbol]) => symbol }));

// OutputNode — applies the MTF filter, returns ISignalDto or null
const mtfSignal = outputNode(async ([higher, lower]) => {
  if (higher.noTrades) return null;
  if (lower.position === 0) return null;
  if (higher.allowShort && lower.position === 1) return null;   // long blocked in downtrend
  if (higher.allowLong  && lower.position === -1) return null;  // short blocked in uptrend
  return toSignalDto(randomString(), lower, null);
}, higherTimeframe, lowerTimeframe);

addStrategySchema({
  strategyName: 'mtf_graph_strategy', interval: '5m',
  getSignal: (symbol) => resolve(mtfSignal),
  actions: ['partial_profit_action', 'breakeven_action'],
});
```

双松节点解 **平行**;其输入结果流入 `compute`替换脚本——或增加第三个过滤节点——不需要修改战略登记.

* * *

## 模型

按设计分为两层:a **低级别运行时间接口** (单位:千美元)`INode`串行到一个DB 重建,没有建造者,和a **高级作者 API** (单位:千美元)`TypedNode` + 键 `sourceNode`编号 :`outputNode`)给出了完整的类型推论. 您与构建者一起写;运行时间和存储使用接口.

-   📊 **DAG 执行** ——节点按地形顺序解决自下而上 `Promise.all` 平行主义.
-   🔒 **类型安全值** ——TypeScript通过通义来推断出每个节点的返回类型(`OutputNode<[SourceNode<number>, SourceNode<string>], …>`) (中文(简体) ).
-   💾 **DB 准备** —— 说 `serialize`编号 :`deserialize` 将图表转换为平面 `IFlatNode[]` 列表为 `id`编号 :`nodeIds`。 。 。 .
-   🔌 **获取上下文** —— 说 `SourceNode.fetch` 接收 `(symbol, when, currentPrice, exchangeName)` 从执行上下文自动.

* * *

## 正在编写 API

构建器 API — sourceNode / 输出 Node / 分辨率

`outputNode` 推断类型 `values` 内 `compute` 从您经过的节点:

```typescript
import { sourceNode, outputNode, resolve } from '@backtest-kit/graph';

const closePrice = sourceNode(async (symbol, when, currentPrice, exchangeName) => {
  const candles = await getCandles(symbol, '1h', 1, exchangeName);
  return candles[0].close;                       // SourceNode<number>
});
const volume = sourceNode(async (symbol, when, currentPrice, exchangeName) => {
  const candles = await getCandles(symbol, '1h', 1, exchangeName);
  return candles[0].volume;                      // SourceNode<number>
});

const vwap = outputNode(([price, vol]) => price * vol, closePrice, volume); // price, vol: number
const result = await resolve(vwap);              // Promise<number>, inside a strategy
```
混合类型——按位置的不同推论

```typescript
const price = sourceNode(async (symbol) => 42);        // SourceNode<number>
const name  = sourceNode(async (symbol) => 'BTCUSDT'); // SourceNode<string>
const flag  = sourceNode(async (symbol) => true);      // SourceNode<boolean>

const result = outputNode(
  ([p, n, f]) => `${n}: ${p} (active: ${f})`,          // p: number, n: string, f: boolean
  price, name, flag,
); // OutputNode<[SourceNode<number>, SourceNode<string>, SourceNode<boolean>], string>
```
内置匿名组成——单一对象文字

```typescript
import { NodeType, TypedNode, resolve } from '@backtest-kit/graph';

const signal: TypedNode = {
  type: NodeType.OutputNode,
  nodes: [
    { type: NodeType.SourceNode, fetch: async (symbol) => extract(await run(File.fromPath('timeframe_4h.pine'),  { symbol, timeframe: '4h',  limit: 100 }), { allowLong: 'AllowLong', allowShort: 'AllowShort', noTrades: 'NoTrades' }) },
    { type: NodeType.SourceNode, fetch: async (symbol) => extract(await run(File.fromPath('timeframe_15m.pine'), { symbol, timeframe: '15m', limit: 100 }), { position: 'Signal', priceOpen: 'Close', priceTakeProfit: 'TakeProfit', priceStopLoss: 'StopLoss' }) },
  ],
  compute: ([higher, lower]) => {
    if (higher.noTrades || lower.position === 0) return null;
    if (higher.allowShort && lower.position === 1) return null;
    if (higher.allowLong  && lower.position === -1) return null;
    return lower.position;
  },
};
const result = await resolve(signal);
```
内在的背向测试-基特策略

```typescript
import { addStrategy } from 'backtest-kit';
import { sourceNode, outputNode, resolve } from '@backtest-kit/graph';

const rsi = sourceNode(async (symbol, when, currentPrice, exchangeName) => 55.2 /* compute RSI */);
const signal = outputNode(([rsiValue]) => rsiValue < 30 ? 1 : rsiValue > 70 ? -1 : 0, rsi);

addStrategy({
  strategyName: 'graph-rsi', interval: '1h', riskName: 'demo',
  getSignal: async (symbol) => {
    const direction = await resolve(signal);     // 1 | -1 | 0
    return direction === 1 ? { position: 'long', /* … */ } : null;
  },
});
```

* * *

## 运行时界面存储( S)

低水平的INDE——人工构造(后去除/DI)

```typescript
import { INode, Value } from '@backtest-kit/graph';
import NodeType from '@backtest-kit/graph/enum/NodeType';

const priceNode: INode = { type: NodeType.SourceNode, description: 'Close price', fetch: async (symbol, when, currentPrice, exchangeName) => 42 };
const doubled:   INode = { type: NodeType.OutputNode, description: 'Doubled price', nodes: [priceNode], compute: ([price]) => (price as number) * 2 };
```

`INode` 没有通用参数—— `values` 内 `compute` 输入为 `Value[]` (单位:千美元)`string | number | boolean | null`) (中文(简体) ). 使用 `TypedNode` + 建造器用于全IntelliSense.

DB 序列化——序列化/去序列化

`serialize` 将图表平整为 `IFlatNode[]`中替换对象引用 `nodes` 与 `nodeIds`· ; `deserialize` 重建树 :

```typescript
import { serialize, deserialize, IFlatNode } from '@backtest-kit/graph';

const flat: IFlatNode[] = serialize([vwap]);
// [ { id:'abc', type:'source_node', nodeIds:[] },          // closePrice
//   { id:'def', type:'source_node', nodeIds:[] },          // volume
//   { id:'ghi', type:'output_node', nodeIds:['abc','def'] } ] // vwap
await db.collection('nodes').insertMany(flat);

const stored = await db.collection('nodes').find().toArray();
const roots: INode[] = deserialize(stored);    // nodes[] re-wired from nodeIds
```

`fetch` 财务报告和审定财务报表 `compute` 为: **没有** 存储 —— 之后在应用程序侧恢复 `deserialize`。 。 。 .

深浮-地貌

按地貌顺序返回所有节点(在父母之前的依赖),通过引用来解去:

```typescript
import { deepFlat } from '@backtest-kit/graph';
const all = deepFlat([vwap]); // [closePrice, volume, vwap]
all.forEach(node => console.log(node.description));
```

* * *

## API 参考

| 导出 | 说明 |
| --- | --- |
| `sourceNode(fetch)` | 建构器-打入源(叶)节点; 2; `fetch(symbol, when, currentPrice, exchangeName)` |
| `outputNode(compute, ...nodes)` | 构建器 — 输入输出节点; 引用 `values` 类型来源 `nodes` |
| `resolve(node)` | 递归解决后端测试- kit 执行上下文中的图表 |
| `serialize(roots)` | 将节点树平整为 `IFlatNode[]` 用于数据库存储 |
| `deserialize(flat)` | 重建一个从 `IFlatNode[]`,返回根节点 |
| `deepFlat(nodes)` | 按地形顺序返回所有节点( 首先依赖) |
| `INode` | 基本运行时间接口(未打出;内部和序列化使用) |
| `TypedNode` | 带有全面IntelliSense著作权的歧视性结合 |
| `IFlatNode` | DB 存储的序列化节点形状(`id`, (中文(简体) ), `type`, (中文(简体) ), `nodeIds`(中文(简体) ) |
| `NodeType` | 埃纳姆 - `SourceNode` (单位:千美元)`source_node`) (中文(简体) ) `OutputNode` (单位:千美元)`output_node`(中文(简体) ) |
| `Value` | `string | number | boolean | null` |
| `ExchangeName` | 交换名别名 `fetch` |

> **完整源图.** `enum/NodeType.ts` • 妇女 `helpers/{node,resolve,serialize,deepFlat}.ts` • 妇女 `interfaces/{Node,TypedNode,FlatNode}.interface.ts` • 妇女 `model/ExchangeName.model.ts` • 妇女 `index.ts` ——上面的每个导出都是这些文件之一;没有输入 `src/` 没有证件.

## \* 贡献

叉/ PR 打开 [GitHub 图像](https://github.com/tripolskypetr/backtest-kit)。 。 。 .

## 许可证

麻省理工学院 [特立奥尔斯基平板电脑](https://github.com/tripolskypetr)

## 常见问题

### @backtest-kit/graph 是什么？

将反向测试-吻合计算编为被打入的定向循环图\. 定义获取市场数据的源节点和计算出衍生值的输出节点——然后按照地理学顺序解决整个图\.

### 如何安装 @backtest-kit/graph？

在项目目录运行 npm install @backtest-kit/graph，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：typescript（^5\.0\.0）、backtest-kit（^23\.7\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @backtest-kit/graph 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @backtest-kit/graph 支持 ESM 还是 CommonJS？

同时提供 ES Module 与 CommonJS 入口，import 和 require\(\) 都可以使用，打包工具会自动选择合适的版本。

### @backtest-kit/graph 可以商用吗？

@backtest-kit/graph 使用 MIT 许可。宽松许可：允许商业使用、修改和再分发，通常只需在分发时保留原版权与许可声明。以上为概括，不构成法律意见，请以许可原文为准。

### @backtest-kit/graph 的下载量有多少？

根据 npm 官方下载统计，@backtest-kit/graph 在 2026/10/08 – 2026/11/06 这 30 天内被下载 2,554 次，日均约 85 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @backtest-kit/graph 还在维护吗？

最新版本 23\.7\.0 发布于 2026/10/29（9 天前）；至今共发布 163 个版本，其中过去 12 个月发布了 163 个；首次发布于 2026/02/19。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

