@backtest-kit/ollama

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

Multi-provider LLM inference library for AI-powered trading strategies. Supports 10+ providers including OpenAI, Claude, DeepSeek, Grok, Mistral with unified API and automatic token rotation.

原始使用文档
文档目录9 节
  1. Why
  2. The provider HOF
  3. Structured output
  4. Prompts
  5. Debugging — dump the conversation
  6. Strategy optimizer — generate runnable strategy code
  7. API reference
  8. 🤝 Contribute
  9. 📜 License

🤖 @backtest-kit/ollama

Universal LLM adapter for backtest-kit trading strategies. One higher-order-function API across 12 providers, schema-enforced structured output, userspace prompt modules, token rotation — plus an LLM strategy optimizer that generates runnable strategy code.

screenshot

Ask DeepWiki npm TypeScript

📚 Docs · 🌟 Reference implementation · 🐙 GitHub

npm install @backtest-kit/ollama backtest-kit agent-swarm-kit

Why

AI strategies normally mean per-provider SDK boilerplate and JSON you can't trust. This package collapses all of it: wrap any async function with a provider HOF and it runs inside that provider's inference context — swap deepseek() → claude() → gpt5() with no other change. Structured output is schema-enforced (Zod or JSON schema via agent-swarm-kit's addOutline), prompts live as memoized userspace modules

  • 🔌 12 providers — OpenAI, Claude, DeepSeek, Grok, Groq, Mistral, Perplexity, Cohere, Alibaba, Hugging Face, Ollama (local), GLM-4 (Z.ai).
  • ⚡ Higher-order functions — wrap an async fn with inference context via di-scoped; same signature in, same out.
  • 🎯 Userspace schema — define your own Zod or JSON schema; structured output enforced with auto-retry + custom validations.
  • 📝 Userspace prompts — load from .cjs modules in config/prompt/, or inline; memoized via functools-kit.
  • 🔄 Token rotation — pass an array of API keys for automatic rotation.
  • 🧬 Strategy optimizer — Optimizer generates complete executable strategy code from LLM analysis across training ranges.

The provider HOF

The whole adapter is one shape, repeated for 12 providers: provider(fn, model, apiKey?) => fn. It returns a function with the same signature as fn, executed inside the provider's inference context (so any agent-swarm-kit completion inside resolves to that provider).

import { deepseek } from '@backtest-kit/ollama';
import { addStrategy } from 'backtest-kit';

addStrategy({
  strategyName: 'llm-signal', interval: '5m',
  // swap deepseek() → claude() / gpt5() / ollama() / groq() with no other change
  getSignal: deepseek(getSignal, 'deepseek-chat', process.env.DEEPSEEK_API_KEY),
});
All 12 providers, base URLs & token rotation
ProviderFunctionInferenceBase URL
OpenAIgpt5()gpt5_inferencehttps://api.openai.com/v1/
Claudeclaude()claude_inferencehttps://api.anthropic.com/v1/
DeepSeekdeepseek()deepseek_inferencehttps://api.deepseek.com/
Grok (xAI)grok()grok_inferencehttps://api.x.ai/v1/
Groqgroq()groq_inferencehttps://api.groq.com/
Mistralmistral()mistral_inferencehttps://api.mistral.ai/v1/
Perplexityperplexity()perplexity_inferencehttps://api.perplexity.ai/
Coherecohere()cohere_inferencehttps://api.cohere.ai/compatibility/v1/
Alibaba (Qwen)alibaba()alibaba_inferencehttps://dashscope-intl.aliyuncs.com/compatible-mode/v1/
Hugging Facehf()hf_inferencehttps://router.huggingface.co/v1/
Ollama (local)ollama()ollama_inferencehttp://localhost:11434/
GLM-4 (Z.ai)glm4()glm4_inferencehttps://open.bigmodel.cn/api/paas/v4/
// apiKey accepts a single key OR an array → automatic rotation across calls
const wrappedFn = ollama(myFn, 'llama3.3:70b', ['key1', 'key2', 'key3']);

All twelve share one signature — <T>(fn: T, model: string, apiKey?: string | string[]) => T — and run fn inside ContextService.runInContext({ apiKey, inference, model }). The matching InferenceName enum + per-provider client/*Provider.client.ts + config/*.ts resolve the actual SDK call.


Structured output

Define a schema (Zod or raw JSON), register it as an outline against this package's CompletionName, and the LLM is forced to return valid JSON — with custom validations that reject bad signals (e.g. "SL must be below entry for LONG").

Zod outline
// schema/Signal.schema.ts
import { z } from 'zod';
export const SignalSchema = z.object({
  position: z.enum(['long', 'short', 'wait']).describe('long: bullish · short: bearish · wait: unclear'),
  price_open: z.number().describe('Entry price in USD'),
  price_stop_loss: z.number().describe('LONG: below entry · SHORT: above entry'),
  price_take_profit: z.number().describe('LONG: above entry · SHORT: below entry'),
  minute_estimated_time: z.number().describe('Estimated minutes to reach TP'),
  risk_note: z.string().describe('Whale manipulation, order-book imbalance, divergences — with numbers'),
});
export type TSignalSchema = z.infer<typeof SignalSchema>;
// outline/signal.outline.ts
import { addOutline } from 'agent-swarm-kit';
import { zodResponseFormat } from 'openai/helpers/zod';
import { SignalSchema, TSignalSchema } from '../schema/Signal.schema';
import { CompletionName } from '@backtest-kit/ollama';

addOutline<TSignalSchema>({
  outlineName: 'SignalOutline',
  completion: CompletionName.RunnerOutlineCompletion,
  format: zodResponseFormat(SignalSchema, 'position_decision'),
  getOutlineHistory: async ({ history, param: messages = [] }) => { await history.push(messages); },
  validations: [{
    validate: ({ data }) => {
      if (data.position === 'long'  && data.price_stop_loss >= data.price_open) throw new Error('LONG: SL must be below entry');
      if (data.position === 'short' && data.price_stop_loss <= data.price_open) throw new Error('SHORT: SL must be above entry');
    },
  }],
});
Raw JSON-schema outline (no Zod)
import { addOutline, IOutlineFormat } from 'agent-swarm-kit';
import { CompletionName } from '@backtest-kit/ollama';

const format: IOutlineFormat = {
  type: 'object',
  properties: {
    take_profit_price: { type: 'number', description: 'Take profit price in USD' },
    stop_loss_price:   { type: 'number', description: 'Stop-loss price in USD' },
    description:       { type: 'string', description: 'User-friendly risk explanation, min 10 sentences' },
    reasoning:         { type: 'string', description: 'Technical analysis, min 15 sentences' },
  },
  required: ['take_profit_price', 'stop_loss_price', 'description', 'reasoning'],
};

addOutline({
  outlineName: 'SignalOutline', format, completion: CompletionName.RunnerOutlineCompletion,
  prompt: 'Generate crypto trading signals from price & volume indicators in JSON.',
  getOutlineHistory: async ({ history, param }) => {
    const report = await ioc.signalReportService.getSignalReport(param);
    await commitReports(history, report);
    await history.push({ role: 'user', content: 'Generate JSON based on reports.' });
  },
  validations: [
    { docDescription: 'Stop-loss vs max loss %',  validate: ({ data }) => { if (data.action === 'buy' && percentDiff(data.current_price, data.stop_loss_price)   > CC_LADDER_STOP_LOSS)   throw new Error(`SL must not exceed -${CC_LADDER_STOP_LOSS}%`); } },
    { docDescription: 'Take-profit vs max profit %', validate: ({ data }) => { if (data.action === 'buy' && percentDiff(data.current_price, data.take_profit_price) > CC_LADDER_TAKE_PROFIT) throw new Error(`TP must not exceed +${CC_LADDER_TAKE_PROFIT}%`); } },
  ],
});

Prompts

Prompt modules receive trading context automatically. system may be a string array or a function of (symbol, strategyName, exchangeName, frameName, backtest); user likewise.

Module file, inline prompt & commitPrompt
// config/prompt/signal.prompt.cjs
module.exports = {
  system: (symbol, strategyName, exchangeName, frameName, backtest) => [
    `You are analyzing ${symbol} on ${exchangeName}`,
    `Strategy: ${strategyName}, Timeframe: ${frameName}`,
    backtest ? 'Backtest mode' : 'Live mode',
  ],
  user: (symbol) => `Analyze ${symbol} and return a trading decision`,
};
import { Module, Prompt, commitPrompt, MessageModel } from '@backtest-kit/ollama';

// from a .cjs module (default baseDir: {cwd}/config/prompt/), memoized
const signalModule = Module.fromPath('./signal.prompt.cjs');
// or inline
const inline = Prompt.fromPrompt({ system: ['You are a trading bot'], user: (symbol) => `Trend for ${symbol}?` });

const messages: MessageModel[] = [];
await commitPrompt(signalModule, messages);   // pushes rendered system + user messages with context

Full strategy: register the outline, build messages from a prompt, request structured JSON, wrap with a provider HOF:

import './outline/signal.outline';
import { deepseek, Module, commitPrompt, MessageModel } from '@backtest-kit/ollama';
import { addStrategy } from 'backtest-kit';
import { json } from 'agent-swarm-kit';

const signalModule = Module.fromPath('./signal.prompt.cjs');
const getSignal = async () => {
  const messages: MessageModel[] = [];
  await commitPrompt(signalModule, messages);
  const { data } = await json('SignalOutline', messages);
  return data;
};
addStrategy({ strategyName: 'llm-signal', interval: '5m',
  getSignal: deepseek(getSignal, 'deepseek-chat', process.env.DEEPSEEK_API_KEY) });

Debugging — dump the conversation

dumpSignalData(signalId, history, signal, outputDir?) archives the full LLM conversation attached to a signal, so an opaque model decision becomes a readable record. Skips if the directory already exists (never overwrites prior runs).

What it writes

Into {outputDir}/{signalId}/ (default ./dump/strategy): 00_system_prompt.md (system messages + output summary), numbered XX_user_message.md / XX_assistant_message.md per turn, and a final XX_llm_output.md with the signal DTO. Call it from getSignal right before returning the signal.


Strategy optimizer — generate runnable strategy code

The most powerful piece, and the one the rest of the package feeds: Optimizer uses an LLM to analyze a symbol across training ranges and emit a complete, executable strategy file — imports, helpers, strategies, walker, and launcher — that you can run with backtest-kit directly.

Optimizer API + addOptimizerSchema + progress events
import { Optimizer, addOptimizerSchema, listenOptimizerProgress } from '@backtest-kit/ollama';

// describe sources, training ranges, strategy/template generation (see IOptimizer* interfaces)
addOptimizerSchema({ optimizerName: 'my-optimizer', /* sources, ranges, strategy, template */ });

listenOptimizerProgress((p) => console.log(p)); // ProgressOptimizerContract

const strategies = await Optimizer.getData('BTCUSDT', { optimizerName: 'my-optimizer' }); // metadata + LLM context per range
const code       = await Optimizer.getCode('BTCUSDT', { optimizerName: 'my-optimizer' }); // full TS/JS source as string
await Optimizer.dump('BTCUSDT', { optimizerName: 'my-optimizer' }, './output');           // writes {optimizerName}_{symbol}.mjs

getData fetches from all sources and builds the LLM conversation per training range; getCode assembles the executable strategy; dump writes it to {optimizerName}_{symbol}.mjs. Companion registry functions: getOptimizerSchema, listOptimizerSchema, and listenError. The engine behind it is common/ClientOptimizer.ts driven by the IOptimizer* interfaces (IOptimizerSchema, IOptimizerSource, IOptimizerStrategy, IOptimizerTemplate, IOptimizerRange, IOptimizerData, IOptimizerFetchArgs, IOptimizerFilterArgs, IOptimizerCallbacks).


API reference

ExportDescription
ollama gpt5 claude deepseek grok groq mistral perplexity cohere alibaba hf glm4Provider HOFs — (fn, model, apiKey?) => fn
CompletionNameCompletion-name enum for agent-swarm-kit outlines (RunnerOutlineCompletion, …)
Module.fromPath(path, baseDir?)Load a prompt .cjs module (default baseDir {cwd}/config/prompt/)
Prompt.fromPrompt(source)Build a prompt from an inline PromptModel
commitPrompt(source, history)Render a Module/Prompt's system+user messages into history
dumpSignalData(id, history, signal, dir?)Archive the LLM conversation for one signal
validate(...)Validate an outline result
Optimizer.getData / .getCode / .dump — LLM strategy-code generation
addOptimizerSchema · getOptimizerSchema · listOptimizerSchemaOptimizer schema registry
listenOptimizerProgress · listenErrorOptimizer progress / error events
MessageModel MessageRole PromptModelMessage & prompt models
IOptimizer* · ProgressOptimizerContractOptimizer interfaces & progress contract
libThe internal engine (IoC container) for advanced use
Complete source map
  • function/signal.function.ts — the 12 provider HOFs. function/{add,get,list,event,setup,validate,history,dump,signal}.ts — registry, events, setLogger, commitPrompt, dumpSignalData.
  • client/*Provider.client.ts (12) — per-provider SDK adapters. config/*.ts — per-provider base URLs/params, ollama.rotate.ts (token rotation), params.ts, emitters.ts.
  • classes/ — Module, Prompt, Optimizer. common/ClientOptimizer.ts — the optimizer engine.
  • enum/ — InferenceName (12), CompletionName. interface/Optimizer.interface.ts, contract/ProgressOptimizer.contract.ts, model/{Message,Prompt}.model.ts.
  • helpers/{toLintMarkdown,toPlainString}.ts, lib/ (IoC: core/{di,provide,types}, services). Nothing in src/ is undocumented.

🤝 Contribute

Fork / PR on GitHub.

📜 License

MIT © tripolskypetr

版本与发布记录

@backtest-kit/ollama 共发布 183 个版本,首次发布于 2026/01/14;过去 12 个月发布了 183 个版本。

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

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

@backtest-kit/ollama 是什么?

Multi-provider LLM inference library for AI-powered trading strategies. Supports 10+ providers including OpenAI, Claude, DeepSeek, Grok, Mistral with unified API and automatic token rotation.

如何安装 @backtest-kit/ollama?

在项目目录运行 npm install @backtest-kit/ollama,或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖:ollama(^0.6.0)、openai(^4.97.0)、groq-sdk(^0.37.0)、typescript(^5.0.0)、backtest-kit(^23.7.0)、@langchain/xai(^0.0.2)、@langchain/core(^0.3.57)、@langchain/openai(^0.4.9)、@huggingface/inference(^4.7.1)。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖,Yarn 需要手动安装。

@backtest-kit/ollama 支持 TypeScript 吗?

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

@backtest-kit/ollama 支持 ESM 还是 CommonJS?

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

@backtest-kit/ollama 可以商用吗?

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

@backtest-kit/ollama 的下载量有多少?

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

@backtest-kit/ollama 还在维护吗?

最新版本 23.7.0 发布于 2026/10/29(9 天前);至今共发布 183 个版本,其中过去 12 个月发布了 183 个;首次发布于 2026/01/14。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。