@backtest-kit/ollama 0.2.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +263 -113
- package/build/index.cjs +500 -755
- package/build/index.mjs +492 -748
- package/package.json +1 -1
- package/types.d.ts +278 -396
package/build/index.cjs
CHANGED
|
@@ -2,15 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
var agentSwarmKit = require('agent-swarm-kit');
|
|
4
4
|
var diScoped = require('di-scoped');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
var module$1 = require('module');
|
|
5
7
|
var diKit = require('di-kit');
|
|
8
|
+
var functoolsKit = require('functools-kit');
|
|
6
9
|
var backtestKit = require('backtest-kit');
|
|
7
|
-
var path = require('path');
|
|
8
10
|
var MarkdownIt = require('markdown-it');
|
|
9
11
|
var sanitizeHtml = require('sanitize-html');
|
|
10
12
|
var promise = require('markdownlint/promise');
|
|
11
13
|
var markdownlint = require('markdownlint');
|
|
12
|
-
var functoolsKit = require('functools-kit');
|
|
13
|
-
var module$1 = require('module');
|
|
14
14
|
var fs = require('fs/promises');
|
|
15
15
|
var OpenAI = require('openai');
|
|
16
16
|
var messages = require('@langchain/core/messages');
|
|
@@ -20,8 +20,6 @@ var inference = require('@huggingface/inference');
|
|
|
20
20
|
var openai = require('@langchain/openai');
|
|
21
21
|
var lodashEs = require('lodash-es');
|
|
22
22
|
var ollama$1 = require('ollama');
|
|
23
|
-
var zod$1 = require('openai/helpers/zod');
|
|
24
|
-
var zod = require('zod');
|
|
25
23
|
|
|
26
24
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
27
25
|
/**
|
|
@@ -37,7 +35,7 @@ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentS
|
|
|
37
35
|
* const completionType = CompletionName.RunnerCompletion;
|
|
38
36
|
* ```
|
|
39
37
|
*/
|
|
40
|
-
|
|
38
|
+
exports.CompletionName = void 0;
|
|
41
39
|
(function (CompletionName) {
|
|
42
40
|
/** Standard completion mode (full response at once) */
|
|
43
41
|
CompletionName["RunnerCompletion"] = "runner_completion";
|
|
@@ -45,8 +43,7 @@ var CompletionName;
|
|
|
45
43
|
CompletionName["RunnerStreamCompletion"] = "runner_stream_completion";
|
|
46
44
|
/** Outline completion mode (structured JSON with schema validation) */
|
|
47
45
|
CompletionName["RunnerOutlineCompletion"] = "runner_outline_completion";
|
|
48
|
-
})(CompletionName || (CompletionName = {}));
|
|
49
|
-
var CompletionName$1 = CompletionName;
|
|
46
|
+
})(exports.CompletionName || (exports.CompletionName = {}));
|
|
50
47
|
|
|
51
48
|
/**
|
|
52
49
|
* Scoped context service for isolated execution contexts.
|
|
@@ -221,14 +218,6 @@ class LoggerService {
|
|
|
221
218
|
*/
|
|
222
219
|
const { provide, inject, init, override } = diKit.createActivator("ollama");
|
|
223
220
|
|
|
224
|
-
/**
|
|
225
|
-
* Common service type identifiers.
|
|
226
|
-
* Services used across the entire application.
|
|
227
|
-
*/
|
|
228
|
-
const commonServices$1 = {
|
|
229
|
-
/** Logger service for application-wide logging */
|
|
230
|
-
loggerService: Symbol("loggerService"),
|
|
231
|
-
};
|
|
232
221
|
/**
|
|
233
222
|
* Base service type identifiers.
|
|
234
223
|
* Core foundational services.
|
|
@@ -236,6 +225,7 @@ const commonServices$1 = {
|
|
|
236
225
|
const baseServices$1 = {
|
|
237
226
|
/** Context service for scoped execution contexts */
|
|
238
227
|
contextService: Symbol('contextService'),
|
|
228
|
+
loggerService: Symbol("loggerService"),
|
|
239
229
|
};
|
|
240
230
|
/**
|
|
241
231
|
* Private service type identifiers.
|
|
@@ -244,8 +234,6 @@ const baseServices$1 = {
|
|
|
244
234
|
const privateServices$1 = {
|
|
245
235
|
/** Runner private service for AI provider operations */
|
|
246
236
|
runnerPrivateService: Symbol('runnerPrivateService'),
|
|
247
|
-
/** Outline private service for structured completions */
|
|
248
|
-
outlinePrivateService: Symbol('outlinePrivateService'),
|
|
249
237
|
};
|
|
250
238
|
/**
|
|
251
239
|
* Public service type identifiers.
|
|
@@ -254,20 +242,29 @@ const privateServices$1 = {
|
|
|
254
242
|
const publicServices$1 = {
|
|
255
243
|
/** Runner public service for context-managed AI operations */
|
|
256
244
|
runnerPublicService: Symbol('runnerPublicService'),
|
|
257
|
-
/** Outline public service for simplified structured completions */
|
|
258
|
-
outlinePublicService: Symbol('outlinePublicService'),
|
|
259
245
|
};
|
|
260
246
|
const promptServices$1 = {
|
|
261
|
-
|
|
247
|
+
resolvePromptService: Symbol('resolvePromptService'),
|
|
248
|
+
};
|
|
249
|
+
const cacheServices$1 = {
|
|
250
|
+
promptCacheService: Symbol('promptCacheService'),
|
|
262
251
|
};
|
|
263
252
|
const markdownServices$1 = {
|
|
264
253
|
outlineMarkdownService: Symbol('outlineMarkdownService'),
|
|
265
254
|
};
|
|
266
|
-
const
|
|
255
|
+
const templateServices$1 = {
|
|
267
256
|
optimizerTemplateService: Symbol('optimizerTemplateService'),
|
|
257
|
+
};
|
|
258
|
+
const schemaServices$1 = {
|
|
268
259
|
optimizerSchemaService: Symbol('optimizerSchemaService'),
|
|
260
|
+
};
|
|
261
|
+
const validationServices$1 = {
|
|
269
262
|
optimizerValidationService: Symbol('optimizerValidationService'),
|
|
263
|
+
};
|
|
264
|
+
const connectionServices$1 = {
|
|
270
265
|
optimizerConnectionService: Symbol('optimizerConnectionService'),
|
|
266
|
+
};
|
|
267
|
+
const globalServices$1 = {
|
|
271
268
|
optimizerGlobalService: Symbol('optimizerGlobalService'),
|
|
272
269
|
};
|
|
273
270
|
/**
|
|
@@ -286,15 +283,66 @@ const optimizerServices$1 = {
|
|
|
286
283
|
* ```
|
|
287
284
|
*/
|
|
288
285
|
const TYPES = {
|
|
289
|
-
...commonServices$1,
|
|
290
286
|
...baseServices$1,
|
|
291
287
|
...promptServices$1,
|
|
288
|
+
...cacheServices$1,
|
|
292
289
|
...markdownServices$1,
|
|
293
|
-
...
|
|
290
|
+
...templateServices$1,
|
|
291
|
+
...schemaServices$1,
|
|
292
|
+
...validationServices$1,
|
|
293
|
+
...connectionServices$1,
|
|
294
|
+
...globalServices$1,
|
|
294
295
|
...privateServices$1,
|
|
295
296
|
...publicServices$1,
|
|
296
297
|
};
|
|
297
298
|
|
|
299
|
+
const PROMPT_TYPE_SYMBOL = Symbol("prompt-type");
|
|
300
|
+
class Prompt {
|
|
301
|
+
constructor(source) {
|
|
302
|
+
this.source = source;
|
|
303
|
+
this.__type__ = PROMPT_TYPE_SYMBOL;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
Prompt.fromPrompt = (source) => {
|
|
307
|
+
if (!source || typeof source !== "object") {
|
|
308
|
+
throw new Error("Source must be a valid PromptModel object");
|
|
309
|
+
}
|
|
310
|
+
return new Prompt(source);
|
|
311
|
+
};
|
|
312
|
+
Prompt.isPrompt = (value) => {
|
|
313
|
+
return (value !== null &&
|
|
314
|
+
typeof value === "object" &&
|
|
315
|
+
value.__type__ === PROMPT_TYPE_SYMBOL);
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
319
|
+
const REQUIRE_MODULE_FN = functoolsKit.memoize(([module]) => module, (module) => {
|
|
320
|
+
const modulePath = require$1.resolve(path.join(module.baseDir, module.path));
|
|
321
|
+
return require$1(modulePath);
|
|
322
|
+
});
|
|
323
|
+
class PromptCacheService {
|
|
324
|
+
constructor() {
|
|
325
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
326
|
+
this.readModule = (module) => {
|
|
327
|
+
this.loggerService.log("promptCacheService readModule", {
|
|
328
|
+
path: module.path,
|
|
329
|
+
baseDir: module.baseDir,
|
|
330
|
+
});
|
|
331
|
+
const source = REQUIRE_MODULE_FN(module);
|
|
332
|
+
return Prompt.fromPrompt(source);
|
|
333
|
+
};
|
|
334
|
+
this.clear = (module) => {
|
|
335
|
+
this.loggerService.log("promptCacheService clear", {
|
|
336
|
+
module,
|
|
337
|
+
});
|
|
338
|
+
if (module) {
|
|
339
|
+
REQUIRE_MODULE_FN.clear(module);
|
|
340
|
+
}
|
|
341
|
+
REQUIRE_MODULE_FN.clear();
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
298
346
|
/**
|
|
299
347
|
* Warning threshold for message size in kilobytes.
|
|
300
348
|
* Messages exceeding this size trigger console warnings.
|
|
@@ -451,203 +499,6 @@ class OutlineMarkdownService {
|
|
|
451
499
|
}
|
|
452
500
|
}
|
|
453
501
|
|
|
454
|
-
/**
|
|
455
|
-
* Enumeration of supported JSON schema outlines.
|
|
456
|
-
*
|
|
457
|
-
* Defines unique identifiers for structured output schemas used with
|
|
458
|
-
* LLM providers. Outlines enforce JSON schema validation for critical
|
|
459
|
-
* data structures like trading signals.
|
|
460
|
-
*
|
|
461
|
-
* @example
|
|
462
|
-
* ```typescript
|
|
463
|
-
* import { OutlineName } from '@backtest-kit/ollama';
|
|
464
|
-
*
|
|
465
|
-
* const outlineName = OutlineName.SignalOutline;
|
|
466
|
-
* ```
|
|
467
|
-
*/
|
|
468
|
-
var OutlineName;
|
|
469
|
-
(function (OutlineName) {
|
|
470
|
-
/** Trading signal JSON schema for position, TP/SL, and risk parameters */
|
|
471
|
-
OutlineName["SignalOutline"] = "signal_outline";
|
|
472
|
-
})(OutlineName || (OutlineName = {}));
|
|
473
|
-
var OutlineName$1 = OutlineName;
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Lints and auto-fixes markdown content using markdownlint rules.
|
|
477
|
-
*
|
|
478
|
-
* Validates markdown syntax and applies automatic fixes for common issues
|
|
479
|
-
* like inconsistent list markers, trailing spaces, and heading styles.
|
|
480
|
-
* Returns the original content if no errors found or fixes cannot be applied.
|
|
481
|
-
*
|
|
482
|
-
* @param content - Raw markdown content to lint
|
|
483
|
-
* @returns Promise resolving to linted markdown content
|
|
484
|
-
*
|
|
485
|
-
* @example
|
|
486
|
-
* ```typescript
|
|
487
|
-
* const markdown = "# Title\n\n\n## Subtitle"; // Multiple blank lines
|
|
488
|
-
* const linted = await toLintMarkdown(markdown);
|
|
489
|
-
* // Returns: "# Title\n\n## Subtitle" (extra blank line removed)
|
|
490
|
-
* ```
|
|
491
|
-
*/
|
|
492
|
-
const toLintMarkdown = async (content) => {
|
|
493
|
-
if (!content) {
|
|
494
|
-
return "";
|
|
495
|
-
}
|
|
496
|
-
const { content: errors } = await promise.lint({ strings: { content } });
|
|
497
|
-
if (!errors.length) {
|
|
498
|
-
return content;
|
|
499
|
-
}
|
|
500
|
-
const value = markdownlint.applyFixes(content, errors);
|
|
501
|
-
return value ? value : content;
|
|
502
|
-
};
|
|
503
|
-
|
|
504
|
-
/**
|
|
505
|
-
* Converts markdown content to plain text with Telegram-compatible HTML formatting.
|
|
506
|
-
*
|
|
507
|
-
* Processes markdown through three stages:
|
|
508
|
-
* 1. Lints and fixes markdown using markdownlint
|
|
509
|
-
* 2. Renders markdown to HTML using markdown-it
|
|
510
|
-
* 3. Sanitizes HTML to Telegram-compatible subset
|
|
511
|
-
*
|
|
512
|
-
* Supported tags: b, i, a, code, pre, s, u, tg-spoiler, blockquote, br
|
|
513
|
-
* Transforms: headings removed, lists to bullets, multiple newlines collapsed
|
|
514
|
-
*
|
|
515
|
-
* @param content - Raw markdown content
|
|
516
|
-
* @returns Promise resolving to sanitized plain text with HTML formatting
|
|
517
|
-
*
|
|
518
|
-
* @example
|
|
519
|
-
* ```typescript
|
|
520
|
-
* const markdown = "# Title\n**Bold** and *italic*\n- Item 1\n- Item 2";
|
|
521
|
-
* const plain = await toPlainString(markdown);
|
|
522
|
-
* // Returns: "Bold and italic\n• Item 1\n• Item 2"
|
|
523
|
-
* ```
|
|
524
|
-
*/
|
|
525
|
-
const toPlainString = async (content) => {
|
|
526
|
-
if (!content) {
|
|
527
|
-
return "";
|
|
528
|
-
}
|
|
529
|
-
const markdown = await toLintMarkdown(content);
|
|
530
|
-
const md = new MarkdownIt({
|
|
531
|
-
html: false,
|
|
532
|
-
breaks: true,
|
|
533
|
-
linkify: true,
|
|
534
|
-
typographer: true,
|
|
535
|
-
});
|
|
536
|
-
let telegramHtml = md.render(markdown);
|
|
537
|
-
telegramHtml = sanitizeHtml(telegramHtml, {
|
|
538
|
-
allowedTags: [
|
|
539
|
-
"b",
|
|
540
|
-
"i",
|
|
541
|
-
"a",
|
|
542
|
-
"code",
|
|
543
|
-
"pre",
|
|
544
|
-
"s",
|
|
545
|
-
"u",
|
|
546
|
-
"tg-spoiler",
|
|
547
|
-
"blockquote",
|
|
548
|
-
"br",
|
|
549
|
-
],
|
|
550
|
-
allowedAttributes: {
|
|
551
|
-
a: ["href"],
|
|
552
|
-
},
|
|
553
|
-
transformTags: {
|
|
554
|
-
h1: "",
|
|
555
|
-
h2: "",
|
|
556
|
-
h3: "",
|
|
557
|
-
h4: "",
|
|
558
|
-
h5: "",
|
|
559
|
-
h6: "",
|
|
560
|
-
a: "",
|
|
561
|
-
strong: "",
|
|
562
|
-
em: "",
|
|
563
|
-
p: () => "",
|
|
564
|
-
ul: () => "",
|
|
565
|
-
li: () => "• ",
|
|
566
|
-
ol: () => "",
|
|
567
|
-
hr: () => "\n",
|
|
568
|
-
br: () => "\n",
|
|
569
|
-
div: () => "",
|
|
570
|
-
},
|
|
571
|
-
});
|
|
572
|
-
return telegramHtml.replaceAll(/\n[\s\n]*\n/g, "\n").trim();
|
|
573
|
-
};
|
|
574
|
-
|
|
575
|
-
/**
|
|
576
|
-
* Private service for processing structured outline completions.
|
|
577
|
-
*
|
|
578
|
-
* Handles the core logic for executing outline-based AI completions with schema validation.
|
|
579
|
-
* Processes AI responses through the agent-swarm-kit json function to extract and validate
|
|
580
|
-
* structured trading signal data.
|
|
581
|
-
*
|
|
582
|
-
* Key features:
|
|
583
|
-
* - JSON schema validation using agent-swarm-kit
|
|
584
|
-
* - Trading signal extraction and transformation
|
|
585
|
-
* - Type conversion for numeric fields
|
|
586
|
-
* - Markdown formatting cleanup for notes
|
|
587
|
-
* - Error handling for validation failures
|
|
588
|
-
*
|
|
589
|
-
* @example
|
|
590
|
-
* ```typescript
|
|
591
|
-
* const outlinePrivate = inject<OutlinePrivateService>(TYPES.outlinePrivateService);
|
|
592
|
-
* const signal = await outlinePrivate.getCompletion([
|
|
593
|
-
* { role: "user", content: "Analyze market" }
|
|
594
|
-
* ]);
|
|
595
|
-
* ```
|
|
596
|
-
*/
|
|
597
|
-
class OutlinePrivateService {
|
|
598
|
-
constructor() {
|
|
599
|
-
/** Logger service for operation tracking */
|
|
600
|
-
this.loggerService = inject(TYPES.loggerService);
|
|
601
|
-
/**
|
|
602
|
-
* Processes outline completion messages and extracts structured signal data.
|
|
603
|
-
*
|
|
604
|
-
* Sends messages to the AI provider, validates the response against the signal schema,
|
|
605
|
-
* and transforms the data into a structured format. Returns null if the AI decides
|
|
606
|
-
* to wait (no position).
|
|
607
|
-
*
|
|
608
|
-
* @param messages - Array of conversation messages for the AI
|
|
609
|
-
* @returns Promise resolving to structured signal data or null if position is "wait"
|
|
610
|
-
* @throws Error if validation fails or AI returns an error
|
|
611
|
-
*
|
|
612
|
-
* @example
|
|
613
|
-
* ```typescript
|
|
614
|
-
* const signal = await outlinePrivateService.getCompletion([
|
|
615
|
-
* { role: "system", content: "Trading analyst role" },
|
|
616
|
-
* { role: "user", content: "Market analysis data..." }
|
|
617
|
-
* ]);
|
|
618
|
-
*
|
|
619
|
-
* if (signal) {
|
|
620
|
-
* console.log(`Position: ${signal.position}`);
|
|
621
|
-
* console.log(`Entry: ${signal.priceOpen}`);
|
|
622
|
-
* console.log(`SL: ${signal.priceStopLoss}`);
|
|
623
|
-
* console.log(`TP: ${signal.priceTakeProfit}`);
|
|
624
|
-
* }
|
|
625
|
-
* ```
|
|
626
|
-
*/
|
|
627
|
-
this.getCompletion = async (messages) => {
|
|
628
|
-
this.loggerService.log("outlinePrivateService getCompletion", {
|
|
629
|
-
messages,
|
|
630
|
-
});
|
|
631
|
-
const { data, resultId, error } = await agentSwarmKit.json(OutlineName$1.SignalOutline, messages);
|
|
632
|
-
if (error) {
|
|
633
|
-
throw new Error(error);
|
|
634
|
-
}
|
|
635
|
-
if (data.position === "wait") {
|
|
636
|
-
return null;
|
|
637
|
-
}
|
|
638
|
-
return {
|
|
639
|
-
id: resultId,
|
|
640
|
-
position: data.position,
|
|
641
|
-
minuteEstimatedTime: +data.minute_estimated_time,
|
|
642
|
-
priceStopLoss: +data.price_stop_loss,
|
|
643
|
-
priceTakeProfit: +data.price_take_profit,
|
|
644
|
-
note: await toPlainString(data.risk_note),
|
|
645
|
-
priceOpen: data.price_open ? +data.price_open : undefined,
|
|
646
|
-
};
|
|
647
|
-
};
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
|
|
651
502
|
/**
|
|
652
503
|
* Private service managing AI inference provider registry and execution.
|
|
653
504
|
*
|
|
@@ -768,47 +619,19 @@ class RunnerPrivateService {
|
|
|
768
619
|
}
|
|
769
620
|
}
|
|
770
621
|
|
|
771
|
-
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
772
|
-
/**
|
|
773
|
-
* Default fallback prompt configuration.
|
|
774
|
-
* Used when signal.prompt.cjs file is not found.
|
|
775
|
-
*/
|
|
776
|
-
const DEFAULT_PROMPT = {
|
|
777
|
-
user: "",
|
|
778
|
-
system: [],
|
|
779
|
-
};
|
|
780
|
-
/**
|
|
781
|
-
* Lazy-loads and caches signal prompt configuration.
|
|
782
|
-
* Attempts to load from config/prompt/signal.prompt.cjs, falls back to DEFAULT_PROMPT if not found.
|
|
783
|
-
* Uses singleshot pattern to ensure configuration is loaded only once.
|
|
784
|
-
* @returns Prompt configuration with system and user prompts
|
|
785
|
-
*/
|
|
786
|
-
const GET_PROMPT_FN = functoolsKit.singleshot(() => {
|
|
787
|
-
try {
|
|
788
|
-
const modulePath = require$1.resolve(path.join(process.cwd(), `./config/prompt/signal.prompt.cjs`));
|
|
789
|
-
console.log(`Using ${modulePath} implementation as signal.prompt.cjs`);
|
|
790
|
-
return require$1(modulePath);
|
|
791
|
-
}
|
|
792
|
-
catch (error) {
|
|
793
|
-
console.log(`Using empty fallback for signal.prompt.cjs`, error);
|
|
794
|
-
return DEFAULT_PROMPT;
|
|
795
|
-
}
|
|
796
|
-
});
|
|
797
622
|
/**
|
|
798
623
|
* Service for managing signal prompts for AI/LLM integrations.
|
|
799
624
|
*
|
|
800
|
-
* Provides access to system and user prompts
|
|
625
|
+
* Provides access to system and user prompts from Prompt.
|
|
801
626
|
* Supports both static prompt arrays and dynamic prompt functions.
|
|
802
627
|
*
|
|
803
628
|
* Key responsibilities:
|
|
804
|
-
* - Lazy-loads prompt configuration from config/prompt/signal.prompt.cjs
|
|
805
629
|
* - Resolves system prompts (static arrays or async functions)
|
|
806
630
|
* - Provides user prompt strings
|
|
807
|
-
* - Falls back to empty prompts if configuration is missing
|
|
808
631
|
*
|
|
809
632
|
* Used for AI-powered signal analysis and strategy recommendations.
|
|
810
633
|
*/
|
|
811
|
-
class
|
|
634
|
+
class ResolvePromptService {
|
|
812
635
|
constructor() {
|
|
813
636
|
this.loggerService = inject(TYPES.loggerService);
|
|
814
637
|
/**
|
|
@@ -819,6 +642,7 @@ class SignalPromptService {
|
|
|
819
642
|
* - Async/sync function returning string array (executed and awaited)
|
|
820
643
|
* - Undefined (returns empty array)
|
|
821
644
|
*
|
|
645
|
+
* @param prompt - Prompt containing the loaded module
|
|
822
646
|
* @param symbol - Trading symbol (e.g., "BTCUSDT")
|
|
823
647
|
* @param strategyName - Strategy identifier
|
|
824
648
|
* @param exchangeName - Exchange identifier
|
|
@@ -826,15 +650,15 @@ class SignalPromptService {
|
|
|
826
650
|
* @param backtest - Whether running in backtest mode
|
|
827
651
|
* @returns Promise resolving to array of system prompt strings
|
|
828
652
|
*/
|
|
829
|
-
this.getSystemPrompt = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
830
|
-
this.loggerService.log("
|
|
653
|
+
this.getSystemPrompt = async (prompt, symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
654
|
+
this.loggerService.log("resolvePromptService getSystemPrompt", {
|
|
831
655
|
symbol,
|
|
832
656
|
strategyName,
|
|
833
657
|
exchangeName,
|
|
834
658
|
frameName,
|
|
835
659
|
backtest,
|
|
836
660
|
});
|
|
837
|
-
const { system } =
|
|
661
|
+
const { system } = prompt.source;
|
|
838
662
|
if (Array.isArray(system)) {
|
|
839
663
|
return system;
|
|
840
664
|
}
|
|
@@ -846,6 +670,7 @@ class SignalPromptService {
|
|
|
846
670
|
/**
|
|
847
671
|
* Retrieves user prompt string for AI input.
|
|
848
672
|
*
|
|
673
|
+
* @param prompt - Prompt containing the loaded module
|
|
849
674
|
* @param symbol - Trading symbol (e.g., "BTCUSDT")
|
|
850
675
|
* @param strategyName - Strategy identifier
|
|
851
676
|
* @param exchangeName - Exchange identifier
|
|
@@ -853,15 +678,15 @@ class SignalPromptService {
|
|
|
853
678
|
* @param backtest - Whether running in backtest mode
|
|
854
679
|
* @returns Promise resolving to user prompt string
|
|
855
680
|
*/
|
|
856
|
-
this.getUserPrompt = async (symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
857
|
-
this.loggerService.log("
|
|
681
|
+
this.getUserPrompt = async (prompt, symbol, strategyName, exchangeName, frameName, backtest) => {
|
|
682
|
+
this.loggerService.log("resolvePromptService getUserPrompt", {
|
|
858
683
|
symbol,
|
|
859
684
|
strategyName,
|
|
860
685
|
exchangeName,
|
|
861
686
|
frameName,
|
|
862
687
|
backtest,
|
|
863
688
|
});
|
|
864
|
-
const { user } =
|
|
689
|
+
const { user } = prompt.source;
|
|
865
690
|
if (typeof user === "string") {
|
|
866
691
|
return user;
|
|
867
692
|
}
|
|
@@ -873,92 +698,6 @@ class SignalPromptService {
|
|
|
873
698
|
}
|
|
874
699
|
}
|
|
875
700
|
|
|
876
|
-
/**
|
|
877
|
-
* Public-facing service for structured AI outline completions.
|
|
878
|
-
*
|
|
879
|
-
* Provides a simplified interface for executing structured AI completions with schema validation.
|
|
880
|
-
* Handles context creation and isolation for outline-based operations.
|
|
881
|
-
* Used for extracting structured data from AI responses (e.g., trading signals).
|
|
882
|
-
*
|
|
883
|
-
* Key features:
|
|
884
|
-
* - Simplified API with automatic context management
|
|
885
|
-
* - JSON schema validation for structured outputs
|
|
886
|
-
* - Support for multiple AI providers
|
|
887
|
-
* - Optional API key parameter with fallback
|
|
888
|
-
* - Logging integration
|
|
889
|
-
*
|
|
890
|
-
* @example
|
|
891
|
-
* ```typescript
|
|
892
|
-
* import { engine } from "./lib";
|
|
893
|
-
* import { InferenceName } from "./enum/InferenceName";
|
|
894
|
-
*
|
|
895
|
-
* const signal = await engine.outlinePublicService.getCompletion(
|
|
896
|
-
* [{ role: "user", content: "Analyze BTC/USDT and decide position" }],
|
|
897
|
-
* InferenceName.ClaudeInference,
|
|
898
|
-
* "claude-3-5-sonnet-20240620",
|
|
899
|
-
* "sk-ant-..."
|
|
900
|
-
* );
|
|
901
|
-
*
|
|
902
|
-
* // Returns structured signal:
|
|
903
|
-
* // {
|
|
904
|
-
* // position: "long",
|
|
905
|
-
* // priceOpen: 50000,
|
|
906
|
-
* // priceStopLoss: 48000,
|
|
907
|
-
* // priceTakeProfit: 52000,
|
|
908
|
-
* // minuteEstimatedTime: 120,
|
|
909
|
-
* // note: "Strong bullish momentum..."
|
|
910
|
-
* // }
|
|
911
|
-
* ```
|
|
912
|
-
*/
|
|
913
|
-
class OutlinePublicService {
|
|
914
|
-
constructor() {
|
|
915
|
-
/** Logger service for operation tracking */
|
|
916
|
-
this.loggerService = inject(TYPES.loggerService);
|
|
917
|
-
/** Private service handling outline completion logic */
|
|
918
|
-
this.outlinePrivateService = inject(TYPES.outlinePrivateService);
|
|
919
|
-
/**
|
|
920
|
-
* Executes a structured outline completion with schema validation.
|
|
921
|
-
*
|
|
922
|
-
* Creates an isolated execution context and processes messages through the AI provider
|
|
923
|
-
* to generate a structured response conforming to a predefined schema.
|
|
924
|
-
*
|
|
925
|
-
* @param messages - Array of conversation messages for the AI
|
|
926
|
-
* @param inference - AI provider identifier
|
|
927
|
-
* @param model - Model name/identifier
|
|
928
|
-
* @param apiKey - Optional API key(s), required for most providers
|
|
929
|
-
* @returns Promise resolving to structured signal data or null if position is "wait"
|
|
930
|
-
*
|
|
931
|
-
* @example
|
|
932
|
-
* ```typescript
|
|
933
|
-
* const result = await outlinePublicService.getCompletion(
|
|
934
|
-
* [
|
|
935
|
-
* { role: "system", content: "You are a trading analyst" },
|
|
936
|
-
* { role: "user", content: "Analyze current BTC market" }
|
|
937
|
-
* ],
|
|
938
|
-
* InferenceName.DeepseekInference,
|
|
939
|
-
* "deepseek-chat",
|
|
940
|
-
* "sk-..."
|
|
941
|
-
* );
|
|
942
|
-
* ```
|
|
943
|
-
*/
|
|
944
|
-
this.getCompletion = async (messages, inference, model, apiKey) => {
|
|
945
|
-
this.loggerService.log("outlinePublicService getCompletion", {
|
|
946
|
-
messages,
|
|
947
|
-
model,
|
|
948
|
-
apiKey,
|
|
949
|
-
inference,
|
|
950
|
-
});
|
|
951
|
-
return await ContextService.runInContext(async () => {
|
|
952
|
-
return await this.outlinePrivateService.getCompletion(messages);
|
|
953
|
-
}, {
|
|
954
|
-
apiKey: apiKey,
|
|
955
|
-
inference,
|
|
956
|
-
model,
|
|
957
|
-
});
|
|
958
|
-
};
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
|
|
962
701
|
/**
|
|
963
702
|
* Public-facing service for AI inference operations with context management.
|
|
964
703
|
*
|
|
@@ -1096,6 +835,106 @@ class RunnerPublicService {
|
|
|
1096
835
|
}
|
|
1097
836
|
}
|
|
1098
837
|
|
|
838
|
+
/**
|
|
839
|
+
* Lints and auto-fixes markdown content using markdownlint rules.
|
|
840
|
+
*
|
|
841
|
+
* Validates markdown syntax and applies automatic fixes for common issues
|
|
842
|
+
* like inconsistent list markers, trailing spaces, and heading styles.
|
|
843
|
+
* Returns the original content if no errors found or fixes cannot be applied.
|
|
844
|
+
*
|
|
845
|
+
* @param content - Raw markdown content to lint
|
|
846
|
+
* @returns Promise resolving to linted markdown content
|
|
847
|
+
*
|
|
848
|
+
* @example
|
|
849
|
+
* ```typescript
|
|
850
|
+
* const markdown = "# Title\n\n\n## Subtitle"; // Multiple blank lines
|
|
851
|
+
* const linted = await toLintMarkdown(markdown);
|
|
852
|
+
* // Returns: "# Title\n\n## Subtitle" (extra blank line removed)
|
|
853
|
+
* ```
|
|
854
|
+
*/
|
|
855
|
+
const toLintMarkdown = async (content) => {
|
|
856
|
+
if (!content) {
|
|
857
|
+
return "";
|
|
858
|
+
}
|
|
859
|
+
const { content: errors } = await promise.lint({ strings: { content } });
|
|
860
|
+
if (!errors.length) {
|
|
861
|
+
return content;
|
|
862
|
+
}
|
|
863
|
+
const value = markdownlint.applyFixes(content, errors);
|
|
864
|
+
return value ? value : content;
|
|
865
|
+
};
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Converts markdown content to plain text with Telegram-compatible HTML formatting.
|
|
869
|
+
*
|
|
870
|
+
* Processes markdown through three stages:
|
|
871
|
+
* 1. Lints and fixes markdown using markdownlint
|
|
872
|
+
* 2. Renders markdown to HTML using markdown-it
|
|
873
|
+
* 3. Sanitizes HTML to Telegram-compatible subset
|
|
874
|
+
*
|
|
875
|
+
* Supported tags: b, i, a, code, pre, s, u, tg-spoiler, blockquote, br
|
|
876
|
+
* Transforms: headings removed, lists to bullets, multiple newlines collapsed
|
|
877
|
+
*
|
|
878
|
+
* @param content - Raw markdown content
|
|
879
|
+
* @returns Promise resolving to sanitized plain text with HTML formatting
|
|
880
|
+
*
|
|
881
|
+
* @example
|
|
882
|
+
* ```typescript
|
|
883
|
+
* const markdown = "# Title\n**Bold** and *italic*\n- Item 1\n- Item 2";
|
|
884
|
+
* const plain = await toPlainString(markdown);
|
|
885
|
+
* // Returns: "Bold and italic\n• Item 1\n• Item 2"
|
|
886
|
+
* ```
|
|
887
|
+
*/
|
|
888
|
+
const toPlainString = async (content) => {
|
|
889
|
+
if (!content) {
|
|
890
|
+
return "";
|
|
891
|
+
}
|
|
892
|
+
const markdown = await toLintMarkdown(content);
|
|
893
|
+
const md = new MarkdownIt({
|
|
894
|
+
html: false,
|
|
895
|
+
breaks: true,
|
|
896
|
+
linkify: true,
|
|
897
|
+
typographer: true,
|
|
898
|
+
});
|
|
899
|
+
let telegramHtml = md.render(markdown);
|
|
900
|
+
telegramHtml = sanitizeHtml(telegramHtml, {
|
|
901
|
+
allowedTags: [
|
|
902
|
+
"b",
|
|
903
|
+
"i",
|
|
904
|
+
"a",
|
|
905
|
+
"code",
|
|
906
|
+
"pre",
|
|
907
|
+
"s",
|
|
908
|
+
"u",
|
|
909
|
+
"tg-spoiler",
|
|
910
|
+
"blockquote",
|
|
911
|
+
"br",
|
|
912
|
+
],
|
|
913
|
+
allowedAttributes: {
|
|
914
|
+
a: ["href"],
|
|
915
|
+
},
|
|
916
|
+
transformTags: {
|
|
917
|
+
h1: "",
|
|
918
|
+
h2: "",
|
|
919
|
+
h3: "",
|
|
920
|
+
h4: "",
|
|
921
|
+
h5: "",
|
|
922
|
+
h6: "",
|
|
923
|
+
a: "",
|
|
924
|
+
strong: "",
|
|
925
|
+
em: "",
|
|
926
|
+
p: () => "",
|
|
927
|
+
ul: () => "",
|
|
928
|
+
li: () => "• ",
|
|
929
|
+
ol: () => "",
|
|
930
|
+
hr: () => "\n",
|
|
931
|
+
br: () => "\n",
|
|
932
|
+
div: () => "",
|
|
933
|
+
},
|
|
934
|
+
});
|
|
935
|
+
return telegramHtml.replaceAll(/\n[\s\n]*\n/g, "\n").trim();
|
|
936
|
+
};
|
|
937
|
+
|
|
1099
938
|
/**
|
|
1100
939
|
* Default template service for generating optimizer code snippets.
|
|
1101
940
|
* Implements all IOptimizerTemplate methods with Ollama LLM integration.
|
|
@@ -2470,46 +2309,62 @@ class OptimizerGlobalService {
|
|
|
2470
2309
|
* This file is imported by lib/index.ts to ensure services are registered
|
|
2471
2310
|
* before the DI container is initialized.
|
|
2472
2311
|
*/
|
|
2473
|
-
/**
|
|
2474
|
-
* Register common services.
|
|
2475
|
-
*/
|
|
2476
|
-
{
|
|
2477
|
-
provide(TYPES.loggerService, () => new LoggerService());
|
|
2478
|
-
}
|
|
2479
2312
|
/**
|
|
2480
2313
|
* Register base services.
|
|
2481
2314
|
*/
|
|
2482
2315
|
{
|
|
2483
2316
|
provide(TYPES.contextService, () => new ContextService());
|
|
2317
|
+
provide(TYPES.loggerService, () => new LoggerService());
|
|
2484
2318
|
}
|
|
2485
2319
|
/**
|
|
2486
2320
|
* Register private services.
|
|
2487
2321
|
*/
|
|
2488
2322
|
{
|
|
2489
2323
|
provide(TYPES.runnerPrivateService, () => new RunnerPrivateService());
|
|
2490
|
-
provide(TYPES.outlinePrivateService, () => new OutlinePrivateService());
|
|
2491
2324
|
}
|
|
2492
2325
|
/**
|
|
2493
2326
|
* Register public services.
|
|
2494
2327
|
*/
|
|
2495
2328
|
{
|
|
2496
2329
|
provide(TYPES.runnerPublicService, () => new RunnerPublicService());
|
|
2497
|
-
provide(TYPES.outlinePublicService, () => new OutlinePublicService());
|
|
2498
2330
|
}
|
|
2499
2331
|
{
|
|
2500
|
-
provide(TYPES.
|
|
2332
|
+
provide(TYPES.resolvePromptService, () => new ResolvePromptService());
|
|
2333
|
+
}
|
|
2334
|
+
{
|
|
2335
|
+
provide(TYPES.promptCacheService, () => new PromptCacheService());
|
|
2501
2336
|
}
|
|
2502
2337
|
{
|
|
2503
2338
|
provide(TYPES.outlineMarkdownService, () => new OutlineMarkdownService());
|
|
2504
2339
|
}
|
|
2505
2340
|
/**
|
|
2506
|
-
* Register
|
|
2341
|
+
* Register template services.
|
|
2507
2342
|
*/
|
|
2508
2343
|
{
|
|
2509
2344
|
provide(TYPES.optimizerTemplateService, () => new OptimizerTemplateService());
|
|
2345
|
+
}
|
|
2346
|
+
/**
|
|
2347
|
+
* Register schema services.
|
|
2348
|
+
*/
|
|
2349
|
+
{
|
|
2510
2350
|
provide(TYPES.optimizerSchemaService, () => new OptimizerSchemaService());
|
|
2351
|
+
}
|
|
2352
|
+
/**
|
|
2353
|
+
* Register validation services.
|
|
2354
|
+
*/
|
|
2355
|
+
{
|
|
2511
2356
|
provide(TYPES.optimizerValidationService, () => new OptimizerValidationService());
|
|
2357
|
+
}
|
|
2358
|
+
/**
|
|
2359
|
+
* Register connection services.
|
|
2360
|
+
*/
|
|
2361
|
+
{
|
|
2512
2362
|
provide(TYPES.optimizerConnectionService, () => new OptimizerConnectionService());
|
|
2363
|
+
}
|
|
2364
|
+
/**
|
|
2365
|
+
* Register global services.
|
|
2366
|
+
*/
|
|
2367
|
+
{
|
|
2513
2368
|
provide(TYPES.optimizerGlobalService, () => new OptimizerGlobalService());
|
|
2514
2369
|
}
|
|
2515
2370
|
|
|
@@ -6486,43 +6341,47 @@ class GLM4Provider {
|
|
|
6486
6341
|
* );
|
|
6487
6342
|
* ```
|
|
6488
6343
|
*/
|
|
6489
|
-
/**
|
|
6490
|
-
* Common service instances.
|
|
6491
|
-
*/
|
|
6492
|
-
const commonServices = {
|
|
6493
|
-
loggerService: inject(TYPES.loggerService),
|
|
6494
|
-
};
|
|
6495
6344
|
/**
|
|
6496
6345
|
* Base service instances.
|
|
6497
6346
|
*/
|
|
6498
6347
|
const baseServices = {
|
|
6499
6348
|
contextService: inject(TYPES.contextService),
|
|
6349
|
+
loggerService: inject(TYPES.loggerService),
|
|
6500
6350
|
};
|
|
6501
6351
|
/**
|
|
6502
6352
|
* Private service instances.
|
|
6503
6353
|
*/
|
|
6504
6354
|
const privateServices = {
|
|
6505
6355
|
runnerPrivateService: inject(TYPES.runnerPrivateService),
|
|
6506
|
-
outlinePrivateService: inject(TYPES.outlinePrivateService),
|
|
6507
6356
|
};
|
|
6508
6357
|
/**
|
|
6509
6358
|
* Public service instances.
|
|
6510
6359
|
*/
|
|
6511
6360
|
const publicServices = {
|
|
6512
6361
|
runnerPublicService: inject(TYPES.runnerPublicService),
|
|
6513
|
-
outlinePublicService: inject(TYPES.outlinePublicService),
|
|
6514
6362
|
};
|
|
6515
6363
|
const promptServices = {
|
|
6516
|
-
|
|
6364
|
+
resolvePromptService: inject(TYPES.resolvePromptService),
|
|
6365
|
+
};
|
|
6366
|
+
const cacheServices = {
|
|
6367
|
+
promptCacheService: inject(TYPES.promptCacheService),
|
|
6517
6368
|
};
|
|
6518
6369
|
const markdownServices = {
|
|
6519
6370
|
outlineMarkdownService: inject(TYPES.outlineMarkdownService),
|
|
6520
6371
|
};
|
|
6521
|
-
const
|
|
6372
|
+
const templateServices = {
|
|
6522
6373
|
optimizerTemplateService: inject(TYPES.optimizerTemplateService),
|
|
6374
|
+
};
|
|
6375
|
+
const schemaServices = {
|
|
6523
6376
|
optimizerSchemaService: inject(TYPES.optimizerSchemaService),
|
|
6377
|
+
};
|
|
6378
|
+
const validationServices = {
|
|
6524
6379
|
optimizerValidationService: inject(TYPES.optimizerValidationService),
|
|
6380
|
+
};
|
|
6381
|
+
const connectionServices = {
|
|
6525
6382
|
optimizerConnectionService: inject(TYPES.optimizerConnectionService),
|
|
6383
|
+
};
|
|
6384
|
+
const globalServices = {
|
|
6526
6385
|
optimizerGlobalService: inject(TYPES.optimizerGlobalService),
|
|
6527
6386
|
};
|
|
6528
6387
|
/**
|
|
@@ -6530,13 +6389,17 @@ const optimizerServices = {
|
|
|
6530
6389
|
* Provides unified access to the entire service layer.
|
|
6531
6390
|
*/
|
|
6532
6391
|
const engine = {
|
|
6533
|
-
...commonServices,
|
|
6534
6392
|
...baseServices,
|
|
6535
6393
|
...privateServices,
|
|
6536
6394
|
...publicServices,
|
|
6537
6395
|
...promptServices,
|
|
6396
|
+
...cacheServices,
|
|
6538
6397
|
...markdownServices,
|
|
6539
|
-
...
|
|
6398
|
+
...templateServices,
|
|
6399
|
+
...schemaServices,
|
|
6400
|
+
...validationServices,
|
|
6401
|
+
...connectionServices,
|
|
6402
|
+
...globalServices,
|
|
6540
6403
|
};
|
|
6541
6404
|
// Initialize DI container
|
|
6542
6405
|
init();
|
|
@@ -6593,11 +6456,11 @@ const LOCAL_RUNNER_FN$2 = functoolsKit.timeout(async (params) => {
|
|
|
6593
6456
|
* ```
|
|
6594
6457
|
*/
|
|
6595
6458
|
agentSwarmKit.addCompletion({
|
|
6596
|
-
completionName: CompletionName.RunnerOutlineCompletion,
|
|
6459
|
+
completionName: exports.CompletionName.RunnerOutlineCompletion,
|
|
6597
6460
|
getCompletion: async (params) => {
|
|
6598
6461
|
const result = await LOCAL_RUNNER_FN$2(params);
|
|
6599
6462
|
if (typeof result === "symbol") {
|
|
6600
|
-
throw new Error(`${CompletionName.RunnerOutlineCompletion} inference timeout`);
|
|
6463
|
+
throw new Error(`${exports.CompletionName.RunnerOutlineCompletion} inference timeout`);
|
|
6601
6464
|
}
|
|
6602
6465
|
return result;
|
|
6603
6466
|
},
|
|
@@ -6636,11 +6499,11 @@ const LOCAL_RUNNER_FN$1 = functoolsKit.timeout(async (params) => {
|
|
|
6636
6499
|
* ```
|
|
6637
6500
|
*/
|
|
6638
6501
|
agentSwarmKit.addCompletion({
|
|
6639
|
-
completionName: CompletionName.RunnerStreamCompletion,
|
|
6502
|
+
completionName: exports.CompletionName.RunnerStreamCompletion,
|
|
6640
6503
|
getCompletion: async (params) => {
|
|
6641
6504
|
const result = await LOCAL_RUNNER_FN$1(params);
|
|
6642
6505
|
if (typeof result === "symbol") {
|
|
6643
|
-
throw new Error(`${CompletionName.RunnerCompletion} inference timeout`);
|
|
6506
|
+
throw new Error(`${exports.CompletionName.RunnerCompletion} inference timeout`);
|
|
6644
6507
|
}
|
|
6645
6508
|
return result;
|
|
6646
6509
|
},
|
|
@@ -6677,457 +6540,367 @@ const LOCAL_RUNNER_FN = functoolsKit.timeout(async (params) => {
|
|
|
6677
6540
|
* ```
|
|
6678
6541
|
*/
|
|
6679
6542
|
agentSwarmKit.addCompletion({
|
|
6680
|
-
completionName: CompletionName.RunnerCompletion,
|
|
6543
|
+
completionName: exports.CompletionName.RunnerCompletion,
|
|
6681
6544
|
getCompletion: async (params) => {
|
|
6682
6545
|
const result = await LOCAL_RUNNER_FN(params);
|
|
6683
6546
|
if (typeof result === "symbol") {
|
|
6684
|
-
throw new Error(`${CompletionName.RunnerCompletion} inference timeout`);
|
|
6547
|
+
throw new Error(`${exports.CompletionName.RunnerCompletion} inference timeout`);
|
|
6685
6548
|
}
|
|
6686
6549
|
return result;
|
|
6687
6550
|
},
|
|
6688
6551
|
});
|
|
6689
6552
|
|
|
6690
6553
|
/**
|
|
6691
|
-
*
|
|
6692
|
-
*
|
|
6693
|
-
* Defines the JSON schema used for LLM-generated trading signals with
|
|
6694
|
-
* comprehensive field descriptions and validation rules. Used with outline
|
|
6695
|
-
* completion to enforce structured output from language models.
|
|
6696
|
-
*
|
|
6697
|
-
* Fields:
|
|
6698
|
-
* - position: Trading direction (long/short/wait)
|
|
6699
|
-
* - price_open: Entry price in USD
|
|
6700
|
-
* - price_stop_loss: Stop-loss price in USD
|
|
6701
|
-
* - price_take_profit: Take-profit price in USD
|
|
6702
|
-
* - minute_estimated_time: Estimated hold duration in minutes
|
|
6703
|
-
* - risk_note: Detailed risk assessment with specific metrics
|
|
6704
|
-
*
|
|
6705
|
-
* @example
|
|
6706
|
-
* ```typescript
|
|
6707
|
-
* import { SignalSchema } from './schema/Signal.schema';
|
|
6708
|
-
*
|
|
6709
|
-
* const signal = SignalSchema.parse({
|
|
6710
|
-
* position: 'long',
|
|
6711
|
-
* price_open: 50000,
|
|
6712
|
-
* price_stop_loss: 49000,
|
|
6713
|
-
* price_take_profit: 52000,
|
|
6714
|
-
* minute_estimated_time: 120,
|
|
6715
|
-
* risk_note: 'RSI oversold at 32%, volume spike +45%'
|
|
6716
|
-
* });
|
|
6717
|
-
* ```
|
|
6718
|
-
*/
|
|
6719
|
-
const SignalSchema = zod.z.object({
|
|
6720
|
-
position: zod.z
|
|
6721
|
-
.enum(["long", "short", "wait"])
|
|
6722
|
-
.describe(functoolsKit.str.newline("Position direction (ALWAYS required):", "long: market shows consistent bullish signals, uptrend or growth potential", "short: market shows consistent bearish signals, downtrend or decline potential", "wait: conflicting signals between timeframes OR unfavorable trading conditions")),
|
|
6723
|
-
price_open: zod.z
|
|
6724
|
-
.number()
|
|
6725
|
-
.describe(functoolsKit.str.newline("Position entry price in USD", "Can be either:", "- Current market price for immediate entry (market order)", "- Price above/below market to open a limit order and wait for its resolve before entering")),
|
|
6726
|
-
price_stop_loss: zod.z
|
|
6727
|
-
.number()
|
|
6728
|
-
.describe(functoolsKit.str.newline("Stop-loss price in USD", "For LONG: price below price_open (protection against decline)", "For SHORT: price above price_open (protection against rise)", "NEVER set SL in 'empty space' without technical justification")),
|
|
6729
|
-
price_take_profit: zod.z
|
|
6730
|
-
.number()
|
|
6731
|
-
.describe(functoolsKit.str.newline("Take-profit price in USD", "For LONG: price above price_open (growth target)", "For SHORT: price below price_open (decline target)", "NEVER set TP based on trend without technical justification")),
|
|
6732
|
-
minute_estimated_time: zod.z
|
|
6733
|
-
.number()
|
|
6734
|
-
.describe(functoolsKit.str.newline("Estimated time to reach Take Profit in minutes", "Calculated based on HONEST technical analysis, using:", "ATR, ADX, MACD, Momentum, Slope and other metrics")),
|
|
6735
|
-
risk_note: zod.z
|
|
6736
|
-
.string()
|
|
6737
|
-
.describe(functoolsKit.str.newline("Description of current market situation risks:", "", "Analyze and specify applicable risks:", "1. Whale manipulations (volume spikes, long shadows, pin bars, candle engulfing, false breakouts)", "2. Order book (order book walls, spoofing, bid/ask imbalance, low liquidity)", "3. P&L history (recurring mistakes on similar patterns)", "4. Time factors (trading session, low liquidity, upcoming events)", "5. Correlations (overall market trend, conflicting trends across timeframes)", "6. Technical risks (indicator divergences, weak volumes, critical levels)", "7. Gaps and anomalies (price gaps, unfilled gaps, movements without volume)", "", "Provide SPECIFIC numbers, percentages and probabilities.")),
|
|
6738
|
-
});
|
|
6739
|
-
|
|
6740
|
-
/**
|
|
6741
|
-
* Trading signal outline schema registration.
|
|
6742
|
-
*
|
|
6743
|
-
* Registers a structured outline for trading signal generation with comprehensive
|
|
6744
|
-
* validation rules. This outline enforces a strict schema for AI-generated trading
|
|
6745
|
-
* signals, ensuring all required fields are present and correctly formatted.
|
|
6746
|
-
*
|
|
6747
|
-
* Schema fields:
|
|
6748
|
-
* - position: Trading direction ("long", "short", or "wait")
|
|
6749
|
-
* - price_open: Entry price for the position
|
|
6750
|
-
* - price_stop_loss: Stop-loss price level
|
|
6751
|
-
* - price_take_profit: Take-profit price level
|
|
6752
|
-
* - minute_estimated_time: Estimated time to reach TP (in minutes)
|
|
6753
|
-
* - risk_note: Risk assessment and reasoning (markdown format)
|
|
6754
|
-
*
|
|
6755
|
-
* Validation rules:
|
|
6756
|
-
* 1. All required fields must be present
|
|
6757
|
-
* 2. Prices must be positive numbers
|
|
6758
|
-
* 3. For LONG: SL < entry < TP
|
|
6759
|
-
* 4. For SHORT: TP < entry < SL
|
|
6760
|
-
* 5. Estimated time must be <= 360 minutes (6 hours)
|
|
6761
|
-
* 6. Wait position skips price validations
|
|
6762
|
-
*
|
|
6763
|
-
* @example
|
|
6764
|
-
* ```typescript
|
|
6765
|
-
* import { json } from "agent-swarm-kit";
|
|
6766
|
-
* import { OutlineName } from "./enum/OutlineName";
|
|
6767
|
-
*
|
|
6768
|
-
* const { data } = await json(OutlineName.SignalOutline, [
|
|
6769
|
-
* { role: "user", content: "Analyze BTC/USDT and decide position" }
|
|
6770
|
-
* ]);
|
|
6771
|
-
*
|
|
6772
|
-
* if (data.position !== "wait") {
|
|
6773
|
-
* console.log(`Position: ${data.position}`);
|
|
6774
|
-
* console.log(`Entry: ${data.price_open}`);
|
|
6775
|
-
* console.log(`SL: ${data.price_stop_loss}`);
|
|
6776
|
-
* console.log(`TP: ${data.price_take_profit}`);
|
|
6777
|
-
* }
|
|
6778
|
-
* ```
|
|
6779
|
-
*/
|
|
6780
|
-
agentSwarmKit.addOutline({
|
|
6781
|
-
outlineName: OutlineName.SignalOutline,
|
|
6782
|
-
completion: CompletionName.RunnerOutlineCompletion,
|
|
6783
|
-
format: zod$1.zodResponseFormat(SignalSchema, "position_open_decision"),
|
|
6784
|
-
getOutlineHistory: async ({ history, param: messages = [] }) => {
|
|
6785
|
-
await history.push(messages);
|
|
6786
|
-
},
|
|
6787
|
-
validations: [
|
|
6788
|
-
{
|
|
6789
|
-
validate: ({ data }) => {
|
|
6790
|
-
if (!data.position) {
|
|
6791
|
-
throw new Error("The position field is not filled");
|
|
6792
|
-
}
|
|
6793
|
-
},
|
|
6794
|
-
docDescription: "Validates that position direction (long/short/wait) is specified.",
|
|
6795
|
-
},
|
|
6796
|
-
{
|
|
6797
|
-
validate: ({ data }) => {
|
|
6798
|
-
if (!data.risk_note) {
|
|
6799
|
-
throw new Error("The risk_note field is not filled");
|
|
6800
|
-
}
|
|
6801
|
-
},
|
|
6802
|
-
docDescription: "Validates that risk description is provided.",
|
|
6803
|
-
},
|
|
6804
|
-
{
|
|
6805
|
-
validate: ({ data }) => {
|
|
6806
|
-
if (data.position !== "wait" &&
|
|
6807
|
-
(!data.price_open || data.price_open <= 0)) {
|
|
6808
|
-
throw new Error("When position='long' or 'short', the price_open field is required and must be positive");
|
|
6809
|
-
}
|
|
6810
|
-
},
|
|
6811
|
-
docDescription: "Validates that opening price is specified and positive when opening a position.",
|
|
6812
|
-
},
|
|
6813
|
-
{
|
|
6814
|
-
validate: ({ data }) => {
|
|
6815
|
-
if (data.position !== "wait" &&
|
|
6816
|
-
(!data.price_stop_loss || data.price_stop_loss <= 0)) {
|
|
6817
|
-
throw new Error("When position='long' or 'short', the price_stop_loss field is required and must be positive");
|
|
6818
|
-
}
|
|
6819
|
-
},
|
|
6820
|
-
docDescription: "Validates that stop-loss is specified when opening a position.",
|
|
6821
|
-
},
|
|
6822
|
-
{
|
|
6823
|
-
validate: ({ data }) => {
|
|
6824
|
-
if (data.position !== "wait" &&
|
|
6825
|
-
(!data.price_take_profit || data.price_take_profit <= 0)) {
|
|
6826
|
-
throw new Error("When position='long' or 'short', the price_take_profit field is required and must be positive");
|
|
6827
|
-
}
|
|
6828
|
-
},
|
|
6829
|
-
docDescription: "Validates that take-profit is specified when opening a position.",
|
|
6830
|
-
},
|
|
6831
|
-
{
|
|
6832
|
-
validate: ({ data }) => {
|
|
6833
|
-
if (data.position === "long" && data.price_open && data.price_stop_loss && data.price_take_profit) {
|
|
6834
|
-
if (data.price_stop_loss >= data.price_open) {
|
|
6835
|
-
throw new Error("For LONG position, price_stop_loss must be below price_open");
|
|
6836
|
-
}
|
|
6837
|
-
if (data.price_take_profit <= data.price_open) {
|
|
6838
|
-
throw new Error("For LONG position, price_take_profit must be above price_open");
|
|
6839
|
-
}
|
|
6840
|
-
}
|
|
6841
|
-
},
|
|
6842
|
-
docDescription: "Validates price correctness for LONG position.",
|
|
6843
|
-
},
|
|
6844
|
-
{
|
|
6845
|
-
validate: ({ data }) => {
|
|
6846
|
-
if (data.position === "short" && data.price_open && data.price_stop_loss && data.price_take_profit) {
|
|
6847
|
-
if (data.price_stop_loss <= data.price_open) {
|
|
6848
|
-
throw new Error("For SHORT position, price_stop_loss must be above price_open");
|
|
6849
|
-
}
|
|
6850
|
-
if (data.price_take_profit >= data.price_open) {
|
|
6851
|
-
throw new Error("For SHORT position, price_take_profit must be below price_open");
|
|
6852
|
-
}
|
|
6853
|
-
}
|
|
6854
|
-
},
|
|
6855
|
-
docDescription: "Validates price correctness for SHORT position.",
|
|
6856
|
-
},
|
|
6857
|
-
{
|
|
6858
|
-
validate: ({ data }) => {
|
|
6859
|
-
if (data.position !== "wait" &&
|
|
6860
|
-
(!data.minute_estimated_time || data.minute_estimated_time <= 0)) {
|
|
6861
|
-
throw new Error("When position='long' or 'short', the minute_estimated_time field is required and must be positive");
|
|
6862
|
-
}
|
|
6863
|
-
},
|
|
6864
|
-
docDescription: "Validates that estimated time to TP is specified when opening a position.",
|
|
6865
|
-
},
|
|
6866
|
-
{
|
|
6867
|
-
validate: ({ data }) => {
|
|
6868
|
-
if (data.position !== "wait" && data.minute_estimated_time > 360) {
|
|
6869
|
-
throw new Error("Estimated time to reach TP exceeds 6 hours (360 minutes). Use position='wait' for low volatility conditions");
|
|
6870
|
-
}
|
|
6871
|
-
},
|
|
6872
|
-
docDescription: "Validates that estimated time to reach TP does not exceed 6 hours.",
|
|
6873
|
-
},
|
|
6874
|
-
],
|
|
6875
|
-
});
|
|
6876
|
-
|
|
6877
|
-
/**
|
|
6878
|
-
* Bootstrap module for agent-swarm-kit validation.
|
|
6879
|
-
*
|
|
6880
|
-
* Validates that all completion and outline names are properly registered
|
|
6881
|
-
* with agent-swarm-kit before the application starts. This ensures that
|
|
6882
|
-
* all referenced completions and outlines exist and are correctly configured.
|
|
6554
|
+
* Wrap async function with Ollama inference context.
|
|
6883
6555
|
*
|
|
6884
|
-
*
|
|
6885
|
-
*
|
|
6886
|
-
* - All OutlineName enum values have corresponding registered schemas
|
|
6887
|
-
* - No duplicate registrations exist
|
|
6556
|
+
* Creates a higher-order function that executes the provided async function
|
|
6557
|
+
* within an Ollama inference context. Supports token rotation by passing multiple API keys.
|
|
6888
6558
|
*
|
|
6889
|
-
*
|
|
6890
|
-
*
|
|
6891
|
-
* @throws Error if validation fails (missing or duplicate registrations)
|
|
6892
|
-
*/
|
|
6893
|
-
agentSwarmKit.validate({
|
|
6894
|
-
CompletionName: CompletionName$1,
|
|
6895
|
-
OutlineName: OutlineName$1,
|
|
6896
|
-
});
|
|
6897
|
-
|
|
6898
|
-
/**
|
|
6899
|
-
* Generate structured trading signal from Ollama models.
|
|
6900
|
-
*
|
|
6901
|
-
* Supports token rotation by passing multiple API keys. Automatically enforces
|
|
6902
|
-
* the signal JSON schema defined in Signal.schema.ts.
|
|
6903
|
-
*
|
|
6904
|
-
* @param messages - Array of outline messages (user/assistant/system)
|
|
6559
|
+
* @template T - Async function type
|
|
6560
|
+
* @param fn - Async function to wrap
|
|
6905
6561
|
* @param model - Ollama model name (e.g., "llama3.3:70b")
|
|
6906
6562
|
* @param apiKey - Single API key or array of keys for rotation
|
|
6907
|
-
* @returns
|
|
6563
|
+
* @returns Wrapped function with same signature as input
|
|
6908
6564
|
*
|
|
6909
6565
|
* @example
|
|
6910
6566
|
* ```typescript
|
|
6911
6567
|
* import { ollama } from '@backtest-kit/ollama';
|
|
6912
6568
|
*
|
|
6913
|
-
* const
|
|
6914
|
-
*
|
|
6569
|
+
* const wrappedFn = ollama(myAsyncFn, 'llama3.3:70b', ['key1', 'key2']);
|
|
6570
|
+
* const result = await wrappedFn(args);
|
|
6915
6571
|
* ```
|
|
6916
6572
|
*/
|
|
6917
|
-
const ollama =
|
|
6918
|
-
|
|
6573
|
+
const ollama = (fn, model, apiKey) => {
|
|
6574
|
+
const wrappedFn = async (args) => {
|
|
6575
|
+
return await ContextService.runInContext(async () => {
|
|
6576
|
+
return await fn(...args);
|
|
6577
|
+
}, {
|
|
6578
|
+
apiKey,
|
|
6579
|
+
inference: InferenceName$1.OllamaInference,
|
|
6580
|
+
model,
|
|
6581
|
+
});
|
|
6582
|
+
};
|
|
6583
|
+
return wrappedFn;
|
|
6919
6584
|
};
|
|
6920
6585
|
/**
|
|
6921
|
-
*
|
|
6586
|
+
* Wrap async function with Grok inference context.
|
|
6922
6587
|
*
|
|
6923
|
-
*
|
|
6588
|
+
* Creates a higher-order function that executes the provided async function
|
|
6589
|
+
* within a Grok (xAI) inference context.
|
|
6924
6590
|
*
|
|
6925
|
-
* @
|
|
6591
|
+
* @template T - Async function type
|
|
6592
|
+
* @param fn - Async function to wrap
|
|
6926
6593
|
* @param model - Grok model name (e.g., "grok-beta")
|
|
6927
|
-
* @param apiKey - Single API key
|
|
6928
|
-
* @returns
|
|
6929
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6594
|
+
* @param apiKey - Single API key or array of keys
|
|
6595
|
+
* @returns Wrapped function with same signature as input
|
|
6930
6596
|
*
|
|
6931
6597
|
* @example
|
|
6932
6598
|
* ```typescript
|
|
6933
6599
|
* import { grok } from '@backtest-kit/ollama';
|
|
6934
6600
|
*
|
|
6935
|
-
* const
|
|
6601
|
+
* const wrappedFn = grok(myAsyncFn, 'grok-beta', process.env.GROK_API_KEY);
|
|
6602
|
+
* const result = await wrappedFn(args);
|
|
6936
6603
|
* ```
|
|
6937
6604
|
*/
|
|
6938
|
-
const grok =
|
|
6939
|
-
|
|
6605
|
+
const grok = (fn, model, apiKey) => {
|
|
6606
|
+
const wrappedFn = async (args) => {
|
|
6607
|
+
return await ContextService.runInContext(async () => {
|
|
6608
|
+
return await fn(...args);
|
|
6609
|
+
}, {
|
|
6610
|
+
apiKey,
|
|
6611
|
+
inference: InferenceName$1.GrokInference,
|
|
6612
|
+
model,
|
|
6613
|
+
});
|
|
6614
|
+
};
|
|
6615
|
+
return wrappedFn;
|
|
6940
6616
|
};
|
|
6941
6617
|
/**
|
|
6942
|
-
*
|
|
6618
|
+
* Wrap async function with HuggingFace inference context.
|
|
6943
6619
|
*
|
|
6944
|
-
*
|
|
6620
|
+
* Creates a higher-order function that executes the provided async function
|
|
6621
|
+
* within a HuggingFace Router API inference context.
|
|
6945
6622
|
*
|
|
6946
|
-
* @
|
|
6947
|
-
* @param
|
|
6948
|
-
* @param
|
|
6949
|
-
* @
|
|
6623
|
+
* @template T - Async function type
|
|
6624
|
+
* @param fn - Async function to wrap
|
|
6625
|
+
* @param model - HuggingFace model name (e.g., "meta-llama/Llama-3-70b")
|
|
6626
|
+
* @param apiKey - Single API key or array of keys
|
|
6627
|
+
* @returns Wrapped function with same signature as input
|
|
6950
6628
|
*
|
|
6951
6629
|
* @example
|
|
6952
6630
|
* ```typescript
|
|
6953
6631
|
* import { hf } from '@backtest-kit/ollama';
|
|
6954
6632
|
*
|
|
6955
|
-
* const
|
|
6633
|
+
* const wrappedFn = hf(myAsyncFn, 'meta-llama/Llama-3-70b', process.env.HF_API_KEY);
|
|
6634
|
+
* const result = await wrappedFn(args);
|
|
6956
6635
|
* ```
|
|
6957
6636
|
*/
|
|
6958
|
-
const hf =
|
|
6959
|
-
|
|
6637
|
+
const hf = (fn, model, apiKey) => {
|
|
6638
|
+
const wrappedFn = async (args) => {
|
|
6639
|
+
return await ContextService.runInContext(async () => {
|
|
6640
|
+
return await fn(...args);
|
|
6641
|
+
}, {
|
|
6642
|
+
apiKey,
|
|
6643
|
+
inference: InferenceName$1.HfInference,
|
|
6644
|
+
model,
|
|
6645
|
+
});
|
|
6646
|
+
};
|
|
6647
|
+
return wrappedFn;
|
|
6960
6648
|
};
|
|
6961
6649
|
/**
|
|
6962
|
-
*
|
|
6650
|
+
* Wrap async function with Claude inference context.
|
|
6963
6651
|
*
|
|
6964
|
-
*
|
|
6652
|
+
* Creates a higher-order function that executes the provided async function
|
|
6653
|
+
* within an Anthropic Claude inference context.
|
|
6965
6654
|
*
|
|
6966
|
-
* @
|
|
6655
|
+
* @template T - Async function type
|
|
6656
|
+
* @param fn - Async function to wrap
|
|
6967
6657
|
* @param model - Claude model name (e.g., "claude-3-5-sonnet-20241022")
|
|
6968
|
-
* @param apiKey - Single API key
|
|
6969
|
-
* @returns
|
|
6970
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6658
|
+
* @param apiKey - Single API key or array of keys
|
|
6659
|
+
* @returns Wrapped function with same signature as input
|
|
6971
6660
|
*
|
|
6972
6661
|
* @example
|
|
6973
6662
|
* ```typescript
|
|
6974
6663
|
* import { claude } from '@backtest-kit/ollama';
|
|
6975
6664
|
*
|
|
6976
|
-
* const
|
|
6665
|
+
* const wrappedFn = claude(myAsyncFn, 'claude-3-5-sonnet-20241022', process.env.ANTHROPIC_API_KEY);
|
|
6666
|
+
* const result = await wrappedFn(args);
|
|
6977
6667
|
* ```
|
|
6978
6668
|
*/
|
|
6979
|
-
const claude =
|
|
6980
|
-
|
|
6669
|
+
const claude = (fn, model, apiKey) => {
|
|
6670
|
+
const wrappedFn = async (args) => {
|
|
6671
|
+
return await ContextService.runInContext(async () => {
|
|
6672
|
+
return await fn(...args);
|
|
6673
|
+
}, {
|
|
6674
|
+
apiKey,
|
|
6675
|
+
inference: InferenceName$1.ClaudeInference,
|
|
6676
|
+
model,
|
|
6677
|
+
});
|
|
6678
|
+
};
|
|
6679
|
+
return wrappedFn;
|
|
6981
6680
|
};
|
|
6982
6681
|
/**
|
|
6983
|
-
*
|
|
6682
|
+
* Wrap async function with OpenAI GPT inference context.
|
|
6984
6683
|
*
|
|
6985
|
-
*
|
|
6684
|
+
* Creates a higher-order function that executes the provided async function
|
|
6685
|
+
* within an OpenAI GPT inference context.
|
|
6986
6686
|
*
|
|
6987
|
-
* @
|
|
6687
|
+
* @template T - Async function type
|
|
6688
|
+
* @param fn - Async function to wrap
|
|
6988
6689
|
* @param model - OpenAI model name (e.g., "gpt-4o", "gpt-4-turbo")
|
|
6989
|
-
* @param apiKey - Single API key
|
|
6990
|
-
* @returns
|
|
6991
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6690
|
+
* @param apiKey - Single API key or array of keys
|
|
6691
|
+
* @returns Wrapped function with same signature as input
|
|
6992
6692
|
*
|
|
6993
6693
|
* @example
|
|
6994
6694
|
* ```typescript
|
|
6995
6695
|
* import { gpt5 } from '@backtest-kit/ollama';
|
|
6996
6696
|
*
|
|
6997
|
-
* const
|
|
6697
|
+
* const wrappedFn = gpt5(myAsyncFn, 'gpt-4o', process.env.OPENAI_API_KEY);
|
|
6698
|
+
* const result = await wrappedFn(args);
|
|
6998
6699
|
* ```
|
|
6999
6700
|
*/
|
|
7000
|
-
const gpt5 =
|
|
7001
|
-
|
|
6701
|
+
const gpt5 = (fn, model, apiKey) => {
|
|
6702
|
+
const wrappedFn = async (args) => {
|
|
6703
|
+
return await ContextService.runInContext(async () => {
|
|
6704
|
+
return await fn(...args);
|
|
6705
|
+
}, {
|
|
6706
|
+
apiKey,
|
|
6707
|
+
inference: InferenceName$1.GPT5Inference,
|
|
6708
|
+
model,
|
|
6709
|
+
});
|
|
6710
|
+
};
|
|
6711
|
+
return wrappedFn;
|
|
7002
6712
|
};
|
|
7003
6713
|
/**
|
|
7004
|
-
*
|
|
6714
|
+
* Wrap async function with DeepSeek inference context.
|
|
7005
6715
|
*
|
|
7006
|
-
*
|
|
6716
|
+
* Creates a higher-order function that executes the provided async function
|
|
6717
|
+
* within a DeepSeek AI inference context.
|
|
7007
6718
|
*
|
|
7008
|
-
* @
|
|
6719
|
+
* @template T - Async function type
|
|
6720
|
+
* @param fn - Async function to wrap
|
|
7009
6721
|
* @param model - DeepSeek model name (e.g., "deepseek-chat")
|
|
7010
|
-
* @param apiKey - Single API key
|
|
7011
|
-
* @returns
|
|
7012
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6722
|
+
* @param apiKey - Single API key or array of keys
|
|
6723
|
+
* @returns Wrapped function with same signature as input
|
|
7013
6724
|
*
|
|
7014
6725
|
* @example
|
|
7015
6726
|
* ```typescript
|
|
7016
6727
|
* import { deepseek } from '@backtest-kit/ollama';
|
|
7017
6728
|
*
|
|
7018
|
-
* const
|
|
6729
|
+
* const wrappedFn = deepseek(myAsyncFn, 'deepseek-chat', process.env.DEEPSEEK_API_KEY);
|
|
6730
|
+
* const result = await wrappedFn(args);
|
|
7019
6731
|
* ```
|
|
7020
6732
|
*/
|
|
7021
|
-
const deepseek =
|
|
7022
|
-
|
|
6733
|
+
const deepseek = (fn, model, apiKey) => {
|
|
6734
|
+
const wrappedFn = async (args) => {
|
|
6735
|
+
return await ContextService.runInContext(async () => {
|
|
6736
|
+
return await fn(...args);
|
|
6737
|
+
}, {
|
|
6738
|
+
apiKey,
|
|
6739
|
+
inference: InferenceName$1.DeepseekInference,
|
|
6740
|
+
model,
|
|
6741
|
+
});
|
|
6742
|
+
};
|
|
6743
|
+
return wrappedFn;
|
|
7023
6744
|
};
|
|
7024
6745
|
/**
|
|
7025
|
-
*
|
|
6746
|
+
* Wrap async function with Mistral AI inference context.
|
|
7026
6747
|
*
|
|
7027
|
-
*
|
|
6748
|
+
* Creates a higher-order function that executes the provided async function
|
|
6749
|
+
* within a Mistral AI inference context.
|
|
7028
6750
|
*
|
|
7029
|
-
* @
|
|
6751
|
+
* @template T - Async function type
|
|
6752
|
+
* @param fn - Async function to wrap
|
|
7030
6753
|
* @param model - Mistral model name (e.g., "mistral-large-latest")
|
|
7031
|
-
* @param apiKey - Single API key
|
|
7032
|
-
* @returns
|
|
7033
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6754
|
+
* @param apiKey - Single API key or array of keys
|
|
6755
|
+
* @returns Wrapped function with same signature as input
|
|
7034
6756
|
*
|
|
7035
6757
|
* @example
|
|
7036
6758
|
* ```typescript
|
|
7037
6759
|
* import { mistral } from '@backtest-kit/ollama';
|
|
7038
6760
|
*
|
|
7039
|
-
* const
|
|
6761
|
+
* const wrappedFn = mistral(myAsyncFn, 'mistral-large-latest', process.env.MISTRAL_API_KEY);
|
|
6762
|
+
* const result = await wrappedFn(args);
|
|
7040
6763
|
* ```
|
|
7041
6764
|
*/
|
|
7042
|
-
const mistral =
|
|
7043
|
-
|
|
6765
|
+
const mistral = (fn, model, apiKey) => {
|
|
6766
|
+
const wrappedFn = async (args) => {
|
|
6767
|
+
return await ContextService.runInContext(async () => {
|
|
6768
|
+
return await fn(...args);
|
|
6769
|
+
}, {
|
|
6770
|
+
apiKey,
|
|
6771
|
+
inference: InferenceName$1.MistralInference,
|
|
6772
|
+
model,
|
|
6773
|
+
});
|
|
6774
|
+
};
|
|
6775
|
+
return wrappedFn;
|
|
7044
6776
|
};
|
|
7045
6777
|
/**
|
|
7046
|
-
*
|
|
6778
|
+
* Wrap async function with Perplexity AI inference context.
|
|
7047
6779
|
*
|
|
7048
|
-
*
|
|
6780
|
+
* Creates a higher-order function that executes the provided async function
|
|
6781
|
+
* within a Perplexity AI inference context.
|
|
7049
6782
|
*
|
|
7050
|
-
* @
|
|
6783
|
+
* @template T - Async function type
|
|
6784
|
+
* @param fn - Async function to wrap
|
|
7051
6785
|
* @param model - Perplexity model name (e.g., "llama-3.1-sonar-huge-128k-online")
|
|
7052
|
-
* @param apiKey - Single API key
|
|
7053
|
-
* @returns
|
|
7054
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6786
|
+
* @param apiKey - Single API key or array of keys
|
|
6787
|
+
* @returns Wrapped function with same signature as input
|
|
7055
6788
|
*
|
|
7056
6789
|
* @example
|
|
7057
6790
|
* ```typescript
|
|
7058
6791
|
* import { perplexity } from '@backtest-kit/ollama';
|
|
7059
6792
|
*
|
|
7060
|
-
* const
|
|
6793
|
+
* const wrappedFn = perplexity(myAsyncFn, 'llama-3.1-sonar-huge-128k-online', process.env.PERPLEXITY_API_KEY);
|
|
6794
|
+
* const result = await wrappedFn(args);
|
|
7061
6795
|
* ```
|
|
7062
6796
|
*/
|
|
7063
|
-
const perplexity =
|
|
7064
|
-
|
|
6797
|
+
const perplexity = (fn, model, apiKey) => {
|
|
6798
|
+
const wrappedFn = async (args) => {
|
|
6799
|
+
return await ContextService.runInContext(async () => {
|
|
6800
|
+
return await fn(...args);
|
|
6801
|
+
}, {
|
|
6802
|
+
apiKey,
|
|
6803
|
+
inference: InferenceName$1.PerplexityInference,
|
|
6804
|
+
model,
|
|
6805
|
+
});
|
|
6806
|
+
};
|
|
6807
|
+
return wrappedFn;
|
|
7065
6808
|
};
|
|
7066
6809
|
/**
|
|
7067
|
-
*
|
|
6810
|
+
* Wrap async function with Cohere inference context.
|
|
7068
6811
|
*
|
|
7069
|
-
*
|
|
6812
|
+
* Creates a higher-order function that executes the provided async function
|
|
6813
|
+
* within a Cohere AI inference context.
|
|
7070
6814
|
*
|
|
7071
|
-
* @
|
|
6815
|
+
* @template T - Async function type
|
|
6816
|
+
* @param fn - Async function to wrap
|
|
7072
6817
|
* @param model - Cohere model name (e.g., "command-r-plus")
|
|
7073
|
-
* @param apiKey - Single API key
|
|
7074
|
-
* @returns
|
|
7075
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6818
|
+
* @param apiKey - Single API key or array of keys
|
|
6819
|
+
* @returns Wrapped function with same signature as input
|
|
7076
6820
|
*
|
|
7077
6821
|
* @example
|
|
7078
6822
|
* ```typescript
|
|
7079
6823
|
* import { cohere } from '@backtest-kit/ollama';
|
|
7080
6824
|
*
|
|
7081
|
-
* const
|
|
6825
|
+
* const wrappedFn = cohere(myAsyncFn, 'command-r-plus', process.env.COHERE_API_KEY);
|
|
6826
|
+
* const result = await wrappedFn(args);
|
|
7082
6827
|
* ```
|
|
7083
6828
|
*/
|
|
7084
|
-
const cohere =
|
|
7085
|
-
|
|
6829
|
+
const cohere = (fn, model, apiKey) => {
|
|
6830
|
+
const wrappedFn = async (args) => {
|
|
6831
|
+
return await ContextService.runInContext(async () => {
|
|
6832
|
+
return await fn(...args);
|
|
6833
|
+
}, {
|
|
6834
|
+
apiKey,
|
|
6835
|
+
inference: InferenceName$1.CohereInference,
|
|
6836
|
+
model,
|
|
6837
|
+
});
|
|
6838
|
+
};
|
|
6839
|
+
return wrappedFn;
|
|
7086
6840
|
};
|
|
7087
6841
|
/**
|
|
7088
|
-
*
|
|
6842
|
+
* Wrap async function with Alibaba Qwen inference context.
|
|
7089
6843
|
*
|
|
7090
|
-
*
|
|
6844
|
+
* Creates a higher-order function that executes the provided async function
|
|
6845
|
+
* within an Alibaba DashScope API inference context.
|
|
7091
6846
|
*
|
|
7092
|
-
* @
|
|
6847
|
+
* @template T - Async function type
|
|
6848
|
+
* @param fn - Async function to wrap
|
|
7093
6849
|
* @param model - Qwen model name (e.g., "qwen-max")
|
|
7094
|
-
* @param apiKey - Single API key
|
|
7095
|
-
* @returns
|
|
7096
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6850
|
+
* @param apiKey - Single API key or array of keys
|
|
6851
|
+
* @returns Wrapped function with same signature as input
|
|
7097
6852
|
*
|
|
7098
6853
|
* @example
|
|
7099
6854
|
* ```typescript
|
|
7100
6855
|
* import { alibaba } from '@backtest-kit/ollama';
|
|
7101
6856
|
*
|
|
7102
|
-
* const
|
|
6857
|
+
* const wrappedFn = alibaba(myAsyncFn, 'qwen-max', process.env.ALIBABA_API_KEY);
|
|
6858
|
+
* const result = await wrappedFn(args);
|
|
7103
6859
|
* ```
|
|
7104
6860
|
*/
|
|
7105
|
-
const alibaba =
|
|
7106
|
-
|
|
6861
|
+
const alibaba = (fn, model, apiKey) => {
|
|
6862
|
+
const wrappedFn = async (args) => {
|
|
6863
|
+
return await ContextService.runInContext(async () => {
|
|
6864
|
+
return await fn(...args);
|
|
6865
|
+
}, {
|
|
6866
|
+
apiKey,
|
|
6867
|
+
inference: InferenceName$1.AlibabaInference,
|
|
6868
|
+
model,
|
|
6869
|
+
});
|
|
6870
|
+
};
|
|
6871
|
+
return wrappedFn;
|
|
7107
6872
|
};
|
|
7108
6873
|
/**
|
|
7109
|
-
*
|
|
6874
|
+
* Wrap async function with Zhipu AI GLM-4 inference context.
|
|
7110
6875
|
*
|
|
7111
|
-
*
|
|
7112
|
-
*
|
|
6876
|
+
* Creates a higher-order function that executes the provided async function
|
|
6877
|
+
* within a Zhipu AI GLM-4 inference context via OpenAI-compatible Z.ai API.
|
|
7113
6878
|
*
|
|
7114
|
-
* @
|
|
6879
|
+
* @template T - Async function type
|
|
6880
|
+
* @param fn - Async function to wrap
|
|
7115
6881
|
* @param model - GLM-4 model name (e.g., "glm-4-plus", "glm-4-air")
|
|
7116
|
-
* @param apiKey - Single API key
|
|
7117
|
-
* @returns
|
|
7118
|
-
* @throws Error if apiKey is an array (token rotation not supported)
|
|
6882
|
+
* @param apiKey - Single API key or array of keys
|
|
6883
|
+
* @returns Wrapped function with same signature as input
|
|
7119
6884
|
*
|
|
7120
6885
|
* @example
|
|
7121
6886
|
* ```typescript
|
|
7122
6887
|
* import { glm4 } from '@backtest-kit/ollama';
|
|
7123
6888
|
*
|
|
7124
|
-
* const
|
|
7125
|
-
*
|
|
7126
|
-
* console.log(`Entry: ${signal.priceOpen}`);
|
|
6889
|
+
* const wrappedFn = glm4(myAsyncFn, 'glm-4-plus', process.env.ZAI_API_KEY);
|
|
6890
|
+
* const result = await wrappedFn(args);
|
|
7127
6891
|
* ```
|
|
7128
6892
|
*/
|
|
7129
|
-
const glm4 =
|
|
7130
|
-
|
|
6893
|
+
const glm4 = (fn, model, apiKey) => {
|
|
6894
|
+
const wrappedFn = async (args) => {
|
|
6895
|
+
return await ContextService.runInContext(async () => {
|
|
6896
|
+
return await fn(...args);
|
|
6897
|
+
}, {
|
|
6898
|
+
apiKey,
|
|
6899
|
+
inference: InferenceName$1.GLM4Inference,
|
|
6900
|
+
model,
|
|
6901
|
+
});
|
|
6902
|
+
};
|
|
6903
|
+
return wrappedFn;
|
|
7131
6904
|
};
|
|
7132
6905
|
|
|
7133
6906
|
/**
|
|
@@ -7151,64 +6924,6 @@ const setLogger = (logger) => {
|
|
|
7151
6924
|
engine$1.loggerService.setLogger(logger);
|
|
7152
6925
|
};
|
|
7153
6926
|
|
|
7154
|
-
/**
|
|
7155
|
-
* Overrides the default signal format schema for LLM-generated trading signals.
|
|
7156
|
-
*
|
|
7157
|
-
* This function allows customization of the structured output format used by the
|
|
7158
|
-
* SignalOutline. It replaces the default signal schema with a custom Zod schema,
|
|
7159
|
-
* enabling flexible signal structure definitions while maintaining type safety.
|
|
7160
|
-
*
|
|
7161
|
-
* The override affects all subsequent signal generation calls using SignalOutline
|
|
7162
|
-
* until the application restarts or the schema is overridden again.
|
|
7163
|
-
*
|
|
7164
|
-
* @template ZodInput - The Zod schema type used for validation and type inference
|
|
7165
|
-
*
|
|
7166
|
-
* @param {ZodInput} format - Custom Zod schema defining the signal structure.
|
|
7167
|
-
* Must be a valid Zod type (z.object, z.string, etc.)
|
|
7168
|
-
*
|
|
7169
|
-
* @example
|
|
7170
|
-
* ```typescript
|
|
7171
|
-
* import { z } from 'zod';
|
|
7172
|
-
* import { overrideSignalFormat } from '@backtest-kit/ollama';
|
|
7173
|
-
*
|
|
7174
|
-
* // Override with custom signal schema
|
|
7175
|
-
* const CustomSignalSchema = z.object({
|
|
7176
|
-
* position: z.enum(['long', 'short', 'wait']),
|
|
7177
|
-
* price_open: z.number(),
|
|
7178
|
-
* confidence: z.number().min(0).max(100),
|
|
7179
|
-
* custom_field: z.string()
|
|
7180
|
-
* });
|
|
7181
|
-
*
|
|
7182
|
-
* overrideSignalFormat(CustomSignalSchema);
|
|
7183
|
-
* ```
|
|
7184
|
-
*
|
|
7185
|
-
* @example
|
|
7186
|
-
* ```typescript
|
|
7187
|
-
* // Override with simplified schema
|
|
7188
|
-
* const SimpleSignalSchema = z.object({
|
|
7189
|
-
* action: z.enum(['buy', 'sell', 'hold']),
|
|
7190
|
-
* price: z.number()
|
|
7191
|
-
* });
|
|
7192
|
-
*
|
|
7193
|
-
* overrideSignalFormat(SimpleSignalSchema);
|
|
7194
|
-
* ```
|
|
7195
|
-
*
|
|
7196
|
-
* @remarks
|
|
7197
|
-
* - The custom schema replaces the default SignalSchema completely
|
|
7198
|
-
* - Schema name in OpenAI format is always "position_open_decision"
|
|
7199
|
-
* - Changes persist until application restart or next override
|
|
7200
|
-
* - Ensure the custom schema matches your signal processing logic
|
|
7201
|
-
*
|
|
7202
|
-
* @see {@link SignalSchema} - Default signal schema structure
|
|
7203
|
-
* @see {@link OutlineName.SignalOutline} - Outline being overridden
|
|
7204
|
-
*/
|
|
7205
|
-
function overrideSignalFormat(format) {
|
|
7206
|
-
agentSwarmKit.overrideOutline({
|
|
7207
|
-
outlineName: OutlineName$1.SignalOutline,
|
|
7208
|
-
format: zod$1.zodResponseFormat(format, "position_open_decision"),
|
|
7209
|
-
});
|
|
7210
|
-
}
|
|
7211
|
-
|
|
7212
6927
|
const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
|
|
7213
6928
|
/**
|
|
7214
6929
|
* Dumps signal data and LLM conversation history to markdown files.
|
|
@@ -7376,7 +7091,36 @@ async function validate(args = {}) {
|
|
|
7376
7091
|
return await validateInternal(args);
|
|
7377
7092
|
}
|
|
7378
7093
|
|
|
7094
|
+
const MODULE_TYPE_SYMBOL = Symbol("module-type");
|
|
7095
|
+
class Module {
|
|
7096
|
+
constructor(path, baseDir) {
|
|
7097
|
+
this.path = path;
|
|
7098
|
+
this.baseDir = baseDir;
|
|
7099
|
+
this.__type__ = MODULE_TYPE_SYMBOL;
|
|
7100
|
+
}
|
|
7101
|
+
}
|
|
7102
|
+
Module.fromPath = (path$1, baseDir = path.join(process.cwd(), "config/prompt")) => {
|
|
7103
|
+
if (!path$1 || typeof path$1 !== "string" || !path$1.trim()) {
|
|
7104
|
+
throw new Error("Path must be a non-empty string");
|
|
7105
|
+
}
|
|
7106
|
+
return new Module(path$1, baseDir);
|
|
7107
|
+
};
|
|
7108
|
+
Module.isModule = (value) => {
|
|
7109
|
+
return (value !== null &&
|
|
7110
|
+
typeof value === "object" &&
|
|
7111
|
+
value.__type__ === MODULE_TYPE_SYMBOL);
|
|
7112
|
+
};
|
|
7113
|
+
|
|
7379
7114
|
const METHOD_NAME_SIGNAL = "history.commitSignalPromptHistory";
|
|
7115
|
+
const GET_PROMPT_FN = async (source) => {
|
|
7116
|
+
if (Prompt.isPrompt(source)) {
|
|
7117
|
+
return source;
|
|
7118
|
+
}
|
|
7119
|
+
if (Module.isModule(source)) {
|
|
7120
|
+
return await engine$1.promptCacheService.readModule(source);
|
|
7121
|
+
}
|
|
7122
|
+
throw new Error("Source must be a Prompt or Module instance");
|
|
7123
|
+
};
|
|
7380
7124
|
/**
|
|
7381
7125
|
* Commits signal prompt history to the message array.
|
|
7382
7126
|
*
|
|
@@ -7385,40 +7129,40 @@ const METHOD_NAME_SIGNAL = "history.commitSignalPromptHistory";
|
|
|
7385
7129
|
* at the end of the history array if they are not empty.
|
|
7386
7130
|
*
|
|
7387
7131
|
* Context extraction:
|
|
7388
|
-
* - symbol:
|
|
7389
|
-
* - backtest mode: From
|
|
7390
|
-
* - strategyName, exchangeName, frameName: From
|
|
7132
|
+
* - symbol: From getSymbol()
|
|
7133
|
+
* - backtest mode: From getMode()
|
|
7134
|
+
* - strategyName, exchangeName, frameName: From getContext()
|
|
7391
7135
|
*
|
|
7392
|
-
* @param
|
|
7136
|
+
* @param source - Module object containing path to .cjs module
|
|
7393
7137
|
* @param history - Message array to append prompts to
|
|
7394
7138
|
* @returns Promise that resolves when prompts are added
|
|
7395
7139
|
* @throws Error if ExecutionContext or MethodContext is not active
|
|
7396
7140
|
*
|
|
7397
|
-
* @example
|
|
7398
|
-
* ```typescript
|
|
7399
|
-
* const messages: MessageModel[] = [];
|
|
7400
|
-
* await commitSignalPromptHistory("BTCUSDT", messages);
|
|
7401
|
-
* // messages now contains system prompts at start and user prompt at end
|
|
7402
7141
|
* ```
|
|
7403
7142
|
*/
|
|
7404
|
-
async function
|
|
7143
|
+
async function commitPrompt(source, history) {
|
|
7405
7144
|
engine$1.loggerService.log(METHOD_NAME_SIGNAL, {
|
|
7406
|
-
|
|
7145
|
+
source,
|
|
7407
7146
|
});
|
|
7147
|
+
const symbol = await backtestKit.getSymbol();
|
|
7408
7148
|
const { strategyName, exchangeName, frameName } = await backtestKit.getContext();
|
|
7409
7149
|
const mode = await backtestKit.getMode();
|
|
7410
7150
|
const isBacktest = mode === "backtest";
|
|
7411
|
-
const
|
|
7412
|
-
const
|
|
7151
|
+
const prompt = await GET_PROMPT_FN(source);
|
|
7152
|
+
const systemPrompts = await engine$1.resolvePromptService.getSystemPrompt(prompt, symbol, strategyName, exchangeName, frameName, isBacktest);
|
|
7153
|
+
const userPrompt = await engine$1.resolvePromptService.getUserPrompt(prompt, symbol, strategyName, exchangeName, frameName, isBacktest);
|
|
7413
7154
|
if (systemPrompts.length > 0) {
|
|
7414
7155
|
for (const content of systemPrompts) {
|
|
7156
|
+
if (!content.trim()) {
|
|
7157
|
+
continue;
|
|
7158
|
+
}
|
|
7415
7159
|
history.unshift({
|
|
7416
7160
|
role: "system",
|
|
7417
7161
|
content,
|
|
7418
7162
|
});
|
|
7419
7163
|
}
|
|
7420
7164
|
}
|
|
7421
|
-
if (userPrompt && userPrompt.trim()
|
|
7165
|
+
if (userPrompt && userPrompt.trim()) {
|
|
7422
7166
|
history.push({
|
|
7423
7167
|
role: "user",
|
|
7424
7168
|
content: userPrompt,
|
|
@@ -7725,12 +7469,14 @@ class OptimizerUtils {
|
|
|
7725
7469
|
*/
|
|
7726
7470
|
const Optimizer = new OptimizerUtils();
|
|
7727
7471
|
|
|
7472
|
+
exports.Module = Module;
|
|
7728
7473
|
exports.Optimizer = Optimizer;
|
|
7474
|
+
exports.Prompt = Prompt;
|
|
7729
7475
|
exports.addOptimizerSchema = addOptimizerSchema;
|
|
7730
7476
|
exports.alibaba = alibaba;
|
|
7731
7477
|
exports.claude = claude;
|
|
7732
7478
|
exports.cohere = cohere;
|
|
7733
|
-
exports.
|
|
7479
|
+
exports.commitPrompt = commitPrompt;
|
|
7734
7480
|
exports.deepseek = deepseek;
|
|
7735
7481
|
exports.dumpSignalData = dumpSignalData;
|
|
7736
7482
|
exports.getOptimizerSchema = getOptimizerSchema;
|
|
@@ -7744,7 +7490,6 @@ exports.listenError = listenError;
|
|
|
7744
7490
|
exports.listenOptimizerProgress = listenOptimizerProgress;
|
|
7745
7491
|
exports.mistral = mistral;
|
|
7746
7492
|
exports.ollama = ollama;
|
|
7747
|
-
exports.overrideSignalFormat = overrideSignalFormat;
|
|
7748
7493
|
exports.perplexity = perplexity;
|
|
7749
7494
|
exports.setLogger = setLogger;
|
|
7750
7495
|
exports.validate = validate;
|