@backtest-kit/graph

中文文档
23.7.0发布于 2026/10/29MITTypeScriptESM + CJS近 30 天下载 2554

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

中文使用文档
文档目录8 节
  1. 是为了什么
  2. 多时间框架松树战略(犬科的例子)
  3. 模型
  4. 正在编写 API
  5. 运行时界面存储( S)
  6. API 参考
  7. * 贡献
  8. 许可证

@ backtest- kit/ graph

编曲 反测试- kit 以打入的定向循环图计算。 声明 源节点 获取市场数据和 输出节点 ——然后按地貌顺序解决整个图,平行地,完全地排入.

screenshot

Ask DeepWiki npm TypeScript

📚 文档 • 妇女 参考执行情况 • 妇女 GitHub 图像

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 只要趋势与条目不一致——所以一个长长的信号在下行和倒行逆施中被压制.

守则
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 从您经过的节点:

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
混合类型——按位置的不同推论
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>
内置匿名组成——单一对象文字
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);
内在的背向测试-基特策略
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)
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 重建树 :

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。 。 。 .

深浮-地貌

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

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著作权的歧视性结合
IFlatNodeDB 存储的序列化节点形状(id, (中文(简体) ), type, (中文(简体) ), nodeIds(中文(简体) )
NodeType埃纳姆 - SourceNode (单位:千美元)source_node) (中文(简体) ) OutputNode (单位:千美元)output_node(中文(简体) )
Valuestring | 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 图像。 。 。 .

许可证

麻省理工学院 特立奥尔斯基平板电脑

版本与发布记录

@backtest-kit/graph 共发布 163 个版本,首次发布于 2026/02/19;过去 12 个月发布了 163 个版本。

版本发布日期距今
23.7.0latest2026/10/299 天前
23.6.02026/10/299 天前
23.5.02026/10/2613 天前
23.4.02026/10/2613 天前
23.3.02026/10/2514 天前
23.2.02026/10/2414 天前

关于 @backtest-kit/graph 的常见问题

@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 和提交记录判断。