backtest-kit 1.4.10 → 1.4.12
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/build/index.cjs +414 -1
- package/build/index.mjs +414 -2
- package/package.json +1 -1
- package/types.d.ts +135 -2
package/build/index.cjs
CHANGED
|
@@ -7,6 +7,7 @@ var fs = require('fs/promises');
|
|
|
7
7
|
var path = require('path');
|
|
8
8
|
var crypto = require('crypto');
|
|
9
9
|
var os = require('os');
|
|
10
|
+
var fs$1 = require('fs');
|
|
10
11
|
|
|
11
12
|
const GLOBAL_CONFIG = {
|
|
12
13
|
/**
|
|
@@ -162,6 +163,7 @@ const markdownServices$1 = {
|
|
|
162
163
|
walkerMarkdownService: Symbol('walkerMarkdownService'),
|
|
163
164
|
heatMarkdownService: Symbol('heatMarkdownService'),
|
|
164
165
|
partialMarkdownService: Symbol('partialMarkdownService'),
|
|
166
|
+
outlineMarkdownService: Symbol('outlineMarkdownService'),
|
|
165
167
|
};
|
|
166
168
|
const validationServices$1 = {
|
|
167
169
|
exchangeValidationService: Symbol('exchangeValidationService'),
|
|
@@ -7262,6 +7264,118 @@ function formatMetric(value) {
|
|
|
7262
7264
|
}
|
|
7263
7265
|
return value.toFixed(2);
|
|
7264
7266
|
}
|
|
7267
|
+
/**
|
|
7268
|
+
* Creates strategy comparison columns based on metric name.
|
|
7269
|
+
* Dynamically builds column configuration with metric-specific header.
|
|
7270
|
+
*
|
|
7271
|
+
* @param metric - Metric being optimized
|
|
7272
|
+
* @returns Array of column configurations for strategy comparison table
|
|
7273
|
+
*/
|
|
7274
|
+
function createStrategyColumns(metric) {
|
|
7275
|
+
return [
|
|
7276
|
+
{
|
|
7277
|
+
key: "rank",
|
|
7278
|
+
label: "Rank",
|
|
7279
|
+
format: (data, index) => `${index + 1}`,
|
|
7280
|
+
},
|
|
7281
|
+
{
|
|
7282
|
+
key: "strategy",
|
|
7283
|
+
label: "Strategy",
|
|
7284
|
+
format: (data) => data.strategyName,
|
|
7285
|
+
},
|
|
7286
|
+
{
|
|
7287
|
+
key: "metric",
|
|
7288
|
+
label: metric,
|
|
7289
|
+
format: (data) => formatMetric(data.metricValue),
|
|
7290
|
+
},
|
|
7291
|
+
{
|
|
7292
|
+
key: "totalSignals",
|
|
7293
|
+
label: "Total Signals",
|
|
7294
|
+
format: (data) => `${data.stats.totalSignals}`,
|
|
7295
|
+
},
|
|
7296
|
+
{
|
|
7297
|
+
key: "winRate",
|
|
7298
|
+
label: "Win Rate",
|
|
7299
|
+
format: (data) => data.stats.winRate !== null
|
|
7300
|
+
? `${data.stats.winRate.toFixed(2)}%`
|
|
7301
|
+
: "N/A",
|
|
7302
|
+
},
|
|
7303
|
+
{
|
|
7304
|
+
key: "avgPnl",
|
|
7305
|
+
label: "Avg PNL",
|
|
7306
|
+
format: (data) => data.stats.avgPnl !== null
|
|
7307
|
+
? `${data.stats.avgPnl > 0 ? "+" : ""}${data.stats.avgPnl.toFixed(2)}%`
|
|
7308
|
+
: "N/A",
|
|
7309
|
+
},
|
|
7310
|
+
{
|
|
7311
|
+
key: "totalPnl",
|
|
7312
|
+
label: "Total PNL",
|
|
7313
|
+
format: (data) => data.stats.totalPnl !== null
|
|
7314
|
+
? `${data.stats.totalPnl > 0 ? "+" : ""}${data.stats.totalPnl.toFixed(2)}%`
|
|
7315
|
+
: "N/A",
|
|
7316
|
+
},
|
|
7317
|
+
{
|
|
7318
|
+
key: "sharpeRatio",
|
|
7319
|
+
label: "Sharpe Ratio",
|
|
7320
|
+
format: (data) => data.stats.sharpeRatio !== null
|
|
7321
|
+
? `${data.stats.sharpeRatio.toFixed(3)}`
|
|
7322
|
+
: "N/A",
|
|
7323
|
+
},
|
|
7324
|
+
{
|
|
7325
|
+
key: "stdDev",
|
|
7326
|
+
label: "Std Dev",
|
|
7327
|
+
format: (data) => data.stats.stdDev !== null
|
|
7328
|
+
? `${data.stats.stdDev.toFixed(3)}%`
|
|
7329
|
+
: "N/A",
|
|
7330
|
+
},
|
|
7331
|
+
];
|
|
7332
|
+
}
|
|
7333
|
+
/**
|
|
7334
|
+
* Column configuration for PNL table.
|
|
7335
|
+
* Defines all columns for displaying closed signals across strategies.
|
|
7336
|
+
*/
|
|
7337
|
+
const pnlColumns = [
|
|
7338
|
+
{
|
|
7339
|
+
key: "strategy",
|
|
7340
|
+
label: "Strategy",
|
|
7341
|
+
format: (data) => data.strategyName,
|
|
7342
|
+
},
|
|
7343
|
+
{
|
|
7344
|
+
key: "signalId",
|
|
7345
|
+
label: "Signal ID",
|
|
7346
|
+
format: (data) => data.signalId,
|
|
7347
|
+
},
|
|
7348
|
+
{
|
|
7349
|
+
key: "symbol",
|
|
7350
|
+
label: "Symbol",
|
|
7351
|
+
format: (data) => data.symbol,
|
|
7352
|
+
},
|
|
7353
|
+
{
|
|
7354
|
+
key: "position",
|
|
7355
|
+
label: "Position",
|
|
7356
|
+
format: (data) => data.position.toUpperCase(),
|
|
7357
|
+
},
|
|
7358
|
+
{
|
|
7359
|
+
key: "pnl",
|
|
7360
|
+
label: "PNL (net)",
|
|
7361
|
+
format: (data) => `${data.pnl > 0 ? "+" : ""}${data.pnl.toFixed(2)}%`,
|
|
7362
|
+
},
|
|
7363
|
+
{
|
|
7364
|
+
key: "closeReason",
|
|
7365
|
+
label: "Close Reason",
|
|
7366
|
+
format: (data) => data.closeReason,
|
|
7367
|
+
},
|
|
7368
|
+
{
|
|
7369
|
+
key: "openTime",
|
|
7370
|
+
label: "Open Time",
|
|
7371
|
+
format: (data) => new Date(data.openTime).toISOString(),
|
|
7372
|
+
},
|
|
7373
|
+
{
|
|
7374
|
+
key: "closeTime",
|
|
7375
|
+
label: "Close Time",
|
|
7376
|
+
format: (data) => new Date(data.closeTime).toISOString(),
|
|
7377
|
+
},
|
|
7378
|
+
];
|
|
7265
7379
|
/**
|
|
7266
7380
|
* Storage class for accumulating walker results.
|
|
7267
7381
|
* Maintains a list of all strategy results and provides methods to generate reports.
|
|
@@ -7274,9 +7388,12 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
7274
7388
|
this._bestStats = null;
|
|
7275
7389
|
this._bestMetric = null;
|
|
7276
7390
|
this._bestStrategy = null;
|
|
7391
|
+
/** All strategy results for comparison table */
|
|
7392
|
+
this._strategyResults = [];
|
|
7277
7393
|
}
|
|
7278
7394
|
/**
|
|
7279
7395
|
* Adds a strategy result to the storage.
|
|
7396
|
+
* Updates best strategy tracking and accumulates result for comparison table.
|
|
7280
7397
|
*
|
|
7281
7398
|
* @param data - Walker contract with strategy result
|
|
7282
7399
|
*/
|
|
@@ -7290,6 +7407,12 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
7290
7407
|
if (data.strategyName === data.bestStrategy) {
|
|
7291
7408
|
this._bestStats = data.stats;
|
|
7292
7409
|
}
|
|
7410
|
+
// Add strategy result to comparison list
|
|
7411
|
+
this._strategyResults.push({
|
|
7412
|
+
strategyName: data.strategyName,
|
|
7413
|
+
stats: data.stats,
|
|
7414
|
+
metricValue: data.metricValue,
|
|
7415
|
+
});
|
|
7293
7416
|
}
|
|
7294
7417
|
/**
|
|
7295
7418
|
* Calculates walker results from strategy results.
|
|
@@ -7314,10 +7437,79 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
7314
7437
|
bestStrategy: this._bestStrategy,
|
|
7315
7438
|
bestMetric: this._bestMetric,
|
|
7316
7439
|
bestStats: this._bestStats,
|
|
7440
|
+
strategyResults: this._strategyResults,
|
|
7317
7441
|
};
|
|
7318
7442
|
}
|
|
7443
|
+
/**
|
|
7444
|
+
* Generates comparison table for top N strategies (View).
|
|
7445
|
+
* Sorts strategies by metric value and formats as markdown table.
|
|
7446
|
+
*
|
|
7447
|
+
* @param metric - Metric being optimized
|
|
7448
|
+
* @param topN - Number of top strategies to include (default: 10)
|
|
7449
|
+
* @returns Markdown formatted comparison table
|
|
7450
|
+
*/
|
|
7451
|
+
getComparisonTable(metric, topN = 10) {
|
|
7452
|
+
if (this._strategyResults.length === 0) {
|
|
7453
|
+
return "No strategy results available.";
|
|
7454
|
+
}
|
|
7455
|
+
// Sort strategies by metric value (descending)
|
|
7456
|
+
const sortedResults = [...this._strategyResults].sort((a, b) => {
|
|
7457
|
+
const aValue = a.metricValue ?? -Infinity;
|
|
7458
|
+
const bValue = b.metricValue ?? -Infinity;
|
|
7459
|
+
return bValue - aValue;
|
|
7460
|
+
});
|
|
7461
|
+
// Take top N strategies
|
|
7462
|
+
const topStrategies = sortedResults.slice(0, topN);
|
|
7463
|
+
// Get columns configuration
|
|
7464
|
+
const columns = createStrategyColumns(metric);
|
|
7465
|
+
// Build table header
|
|
7466
|
+
const header = columns.map((col) => col.label);
|
|
7467
|
+
const separator = columns.map(() => "---");
|
|
7468
|
+
// Build table rows
|
|
7469
|
+
const rows = topStrategies.map((result, index) => columns.map((col) => col.format(result, index)));
|
|
7470
|
+
const tableData = [header, separator, ...rows];
|
|
7471
|
+
return functoolsKit.str.newline(tableData.map((row) => `| ${row.join(" | ")} |`));
|
|
7472
|
+
}
|
|
7473
|
+
/**
|
|
7474
|
+
* Generates PNL table showing all closed signals across all strategies (View).
|
|
7475
|
+
* Collects all signals from all strategies and formats as markdown table.
|
|
7476
|
+
*
|
|
7477
|
+
* @returns Markdown formatted PNL table
|
|
7478
|
+
*/
|
|
7479
|
+
getPnlTable() {
|
|
7480
|
+
if (this._strategyResults.length === 0) {
|
|
7481
|
+
return "No strategy results available.";
|
|
7482
|
+
}
|
|
7483
|
+
// Collect all closed signals from all strategies
|
|
7484
|
+
const allSignals = [];
|
|
7485
|
+
for (const result of this._strategyResults) {
|
|
7486
|
+
for (const signal of result.stats.signalList) {
|
|
7487
|
+
allSignals.push({
|
|
7488
|
+
strategyName: result.strategyName,
|
|
7489
|
+
signalId: signal.signal.id,
|
|
7490
|
+
symbol: signal.signal.symbol,
|
|
7491
|
+
position: signal.signal.position,
|
|
7492
|
+
pnl: signal.pnl.pnlPercentage,
|
|
7493
|
+
closeReason: signal.closeReason,
|
|
7494
|
+
openTime: signal.signal.pendingAt,
|
|
7495
|
+
closeTime: signal.closeTimestamp,
|
|
7496
|
+
});
|
|
7497
|
+
}
|
|
7498
|
+
}
|
|
7499
|
+
if (allSignals.length === 0) {
|
|
7500
|
+
return "No closed signals available.";
|
|
7501
|
+
}
|
|
7502
|
+
// Build table header
|
|
7503
|
+
const header = pnlColumns.map((col) => col.label);
|
|
7504
|
+
const separator = pnlColumns.map(() => "---");
|
|
7505
|
+
// Build table rows
|
|
7506
|
+
const rows = allSignals.map((signal) => pnlColumns.map((col) => col.format(signal)));
|
|
7507
|
+
const tableData = [header, separator, ...rows];
|
|
7508
|
+
return functoolsKit.str.newline(tableData.map((row) => `| ${row.join(" | ")} |`));
|
|
7509
|
+
}
|
|
7319
7510
|
/**
|
|
7320
7511
|
* Generates markdown report with all strategy results (View).
|
|
7512
|
+
* Includes best strategy summary, comparison table, and PNL table.
|
|
7321
7513
|
*
|
|
7322
7514
|
* @param symbol - Trading symbol
|
|
7323
7515
|
* @param metric - Metric being optimized
|
|
@@ -7326,7 +7518,9 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
7326
7518
|
*/
|
|
7327
7519
|
async getReport(symbol, metric, context) {
|
|
7328
7520
|
const results = await this.getData(symbol, metric, context);
|
|
7329
|
-
|
|
7521
|
+
// Get total signals for best strategy
|
|
7522
|
+
const bestStrategySignals = results.bestStats?.totalSignals ?? 0;
|
|
7523
|
+
return functoolsKit.str.newline(`# Walker Comparison Report: ${results.walkerName}`, "", `**Symbol:** ${results.symbol}`, `**Exchange:** ${results.exchangeName}`, `**Frame:** ${results.frameName}`, `**Optimization Metric:** ${results.metric}`, `**Strategies Tested:** ${results.totalStrategies}`, "", `## Best Strategy: ${results.bestStrategy}`, "", `**Best ${results.metric}:** ${formatMetric(results.bestMetric)}`, `**Total Signals:** ${bestStrategySignals}`, "", "## Top Strategies Comparison", "", this.getComparisonTable(metric, 10), "", "## All Signals (PNL Table)", "", this.getPnlTable(), "", "**Note:** Higher values are better for all metrics except Standard Deviation (lower is better).");
|
|
7330
7524
|
}
|
|
7331
7525
|
/**
|
|
7332
7526
|
* Saves walker report to disk.
|
|
@@ -10714,6 +10908,145 @@ class PartialGlobalService {
|
|
|
10714
10908
|
}
|
|
10715
10909
|
}
|
|
10716
10910
|
|
|
10911
|
+
/**
|
|
10912
|
+
* Warning threshold for message size in kilobytes.
|
|
10913
|
+
* Messages exceeding this size trigger console warnings.
|
|
10914
|
+
*/
|
|
10915
|
+
const WARN_KB = 100;
|
|
10916
|
+
/**
|
|
10917
|
+
* Internal function for dumping signal data to markdown files.
|
|
10918
|
+
* Creates a directory structure with system prompts, user messages, and LLM output.
|
|
10919
|
+
*
|
|
10920
|
+
* @param signalId - Unique identifier for the result
|
|
10921
|
+
* @param history - Array of message models from LLM conversation
|
|
10922
|
+
* @param signal - Signal DTO with trade parameters
|
|
10923
|
+
* @param outputDir - Output directory path (default: "./dump/strategy")
|
|
10924
|
+
* @returns Promise that resolves when all files are written
|
|
10925
|
+
*/
|
|
10926
|
+
const DUMP_SIGNAL_FN = async (signalId, history, signal, outputDir = "./dump/strategy") => {
|
|
10927
|
+
// Extract system messages and system reminders from existing data
|
|
10928
|
+
const systemMessages = history.filter((m) => m.role === "system");
|
|
10929
|
+
const userMessages = history.filter((m) => m.role === "user");
|
|
10930
|
+
const subfolderPath = path.join(outputDir, String(signalId));
|
|
10931
|
+
try {
|
|
10932
|
+
await fs$1.promises.access(subfolderPath);
|
|
10933
|
+
return;
|
|
10934
|
+
}
|
|
10935
|
+
catch {
|
|
10936
|
+
await fs$1.promises.mkdir(subfolderPath, { recursive: true });
|
|
10937
|
+
}
|
|
10938
|
+
{
|
|
10939
|
+
let summary = "# Outline Result Summary\n";
|
|
10940
|
+
{
|
|
10941
|
+
summary += "\n";
|
|
10942
|
+
summary += `**ResultId**: ${String(signalId)}\n`;
|
|
10943
|
+
summary += "\n";
|
|
10944
|
+
}
|
|
10945
|
+
if (signal) {
|
|
10946
|
+
summary += "## Output Data\n\n";
|
|
10947
|
+
summary += "```json\n";
|
|
10948
|
+
summary += JSON.stringify(signal, null, 2);
|
|
10949
|
+
summary += "\n```\n\n";
|
|
10950
|
+
}
|
|
10951
|
+
// Add system messages to summary
|
|
10952
|
+
if (systemMessages.length > 0) {
|
|
10953
|
+
summary += "## System Messages\n\n";
|
|
10954
|
+
systemMessages.forEach((msg, idx) => {
|
|
10955
|
+
summary += `### System Message ${idx + 1}\n\n`;
|
|
10956
|
+
summary += msg.content;
|
|
10957
|
+
summary += "\n";
|
|
10958
|
+
});
|
|
10959
|
+
}
|
|
10960
|
+
const summaryFile = path.join(subfolderPath, "00_system_prompt.md");
|
|
10961
|
+
await fs$1.promises.writeFile(summaryFile, summary, "utf8");
|
|
10962
|
+
}
|
|
10963
|
+
{
|
|
10964
|
+
await Promise.all(Array.from(userMessages.entries()).map(async ([idx, message]) => {
|
|
10965
|
+
const messageNum = String(idx + 1).padStart(2, "0");
|
|
10966
|
+
const contentFileName = `${messageNum}_user_message.md`;
|
|
10967
|
+
const contentFilePath = path.join(subfolderPath, contentFileName);
|
|
10968
|
+
{
|
|
10969
|
+
const messageSizeBytes = Buffer.byteLength(message.content, "utf8");
|
|
10970
|
+
const messageSizeKb = Math.floor(messageSizeBytes / 1024);
|
|
10971
|
+
if (messageSizeKb > WARN_KB) {
|
|
10972
|
+
console.warn(`User message ${idx + 1} is ${messageSizeBytes} bytes (${messageSizeKb}kb), which exceeds warning limit`);
|
|
10973
|
+
}
|
|
10974
|
+
}
|
|
10975
|
+
let content = `# User Input ${idx + 1}\n\n`;
|
|
10976
|
+
content += `**ResultId**: ${String(signalId)}\n\n`;
|
|
10977
|
+
content += message.content;
|
|
10978
|
+
content += "\n";
|
|
10979
|
+
await fs$1.promises.writeFile(contentFilePath, content, "utf8");
|
|
10980
|
+
}));
|
|
10981
|
+
}
|
|
10982
|
+
{
|
|
10983
|
+
const messageNum = String(userMessages.length + 1).padStart(2, "0");
|
|
10984
|
+
const contentFileName = `${messageNum}_llm_output.md`;
|
|
10985
|
+
const contentFilePath = path.join(subfolderPath, contentFileName);
|
|
10986
|
+
let content = "# Full Outline Result\n\n";
|
|
10987
|
+
content += `**ResultId**: ${String(signalId)}\n\n`;
|
|
10988
|
+
if (signal) {
|
|
10989
|
+
content += "## Output Data\n\n";
|
|
10990
|
+
content += "```json\n";
|
|
10991
|
+
content += JSON.stringify(signal, null, 2);
|
|
10992
|
+
content += "\n```\n";
|
|
10993
|
+
}
|
|
10994
|
+
await fs$1.promises.writeFile(contentFilePath, content, "utf8");
|
|
10995
|
+
}
|
|
10996
|
+
};
|
|
10997
|
+
/**
|
|
10998
|
+
* Service for generating markdown documentation from LLM outline results.
|
|
10999
|
+
* Used by AI Strategy Optimizer to save debug logs and conversation history.
|
|
11000
|
+
*
|
|
11001
|
+
* Creates directory structure:
|
|
11002
|
+
* - ./dump/strategy/{signalId}/00_system_prompt.md - System messages and output data
|
|
11003
|
+
* - ./dump/strategy/{signalId}/01_user_message.md - First user input
|
|
11004
|
+
* - ./dump/strategy/{signalId}/02_user_message.md - Second user input
|
|
11005
|
+
* - ./dump/strategy/{signalId}/XX_llm_output.md - Final LLM output
|
|
11006
|
+
*/
|
|
11007
|
+
class OutlineMarkdownService {
|
|
11008
|
+
constructor() {
|
|
11009
|
+
/** Logger service injected via DI */
|
|
11010
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
11011
|
+
/**
|
|
11012
|
+
* Dumps signal data and conversation history to markdown files.
|
|
11013
|
+
* Skips if directory already exists to avoid overwriting previous results.
|
|
11014
|
+
*
|
|
11015
|
+
* Generated files:
|
|
11016
|
+
* - 00_system_prompt.md - System messages and output summary
|
|
11017
|
+
* - XX_user_message.md - Each user message in separate file (numbered)
|
|
11018
|
+
* - XX_llm_output.md - Final LLM output with signal data
|
|
11019
|
+
*
|
|
11020
|
+
* @param signalId - Unique identifier for the result (used as directory name)
|
|
11021
|
+
* @param history - Array of message models from LLM conversation
|
|
11022
|
+
* @param signal - Signal DTO with trade parameters (priceOpen, TP, SL, etc.)
|
|
11023
|
+
* @param outputDir - Output directory path (default: "./dump/strategy")
|
|
11024
|
+
* @returns Promise that resolves when all files are written
|
|
11025
|
+
*
|
|
11026
|
+
* @example
|
|
11027
|
+
* ```typescript
|
|
11028
|
+
* await outlineService.dumpSignal(
|
|
11029
|
+
* "strategy-1",
|
|
11030
|
+
* conversationHistory,
|
|
11031
|
+
* { position: "long", priceTakeProfit: 51000, priceStopLoss: 49000, minuteEstimatedTime: 60 }
|
|
11032
|
+
* );
|
|
11033
|
+
* // Creates: ./dump/strategy/strategy-1/00_system_prompt.md
|
|
11034
|
+
* // ./dump/strategy/strategy-1/01_user_message.md
|
|
11035
|
+
* // ./dump/strategy/strategy-1/02_llm_output.md
|
|
11036
|
+
* ```
|
|
11037
|
+
*/
|
|
11038
|
+
this.dumpSignal = async (signalId, history, signal, outputDir = "./dump/strategy") => {
|
|
11039
|
+
this.loggerService.log("outlineMarkdownService dumpSignal", {
|
|
11040
|
+
signalId,
|
|
11041
|
+
history,
|
|
11042
|
+
signal,
|
|
11043
|
+
outputDir,
|
|
11044
|
+
});
|
|
11045
|
+
return await DUMP_SIGNAL_FN(signalId, history, signal, outputDir);
|
|
11046
|
+
};
|
|
11047
|
+
}
|
|
11048
|
+
}
|
|
11049
|
+
|
|
10717
11050
|
{
|
|
10718
11051
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
10719
11052
|
}
|
|
@@ -10771,6 +11104,7 @@ class PartialGlobalService {
|
|
|
10771
11104
|
provide(TYPES.walkerMarkdownService, () => new WalkerMarkdownService());
|
|
10772
11105
|
provide(TYPES.heatMarkdownService, () => new HeatMarkdownService());
|
|
10773
11106
|
provide(TYPES.partialMarkdownService, () => new PartialMarkdownService());
|
|
11107
|
+
provide(TYPES.outlineMarkdownService, () => new OutlineMarkdownService());
|
|
10774
11108
|
}
|
|
10775
11109
|
{
|
|
10776
11110
|
provide(TYPES.exchangeValidationService, () => new ExchangeValidationService());
|
|
@@ -10842,6 +11176,7 @@ const markdownServices = {
|
|
|
10842
11176
|
walkerMarkdownService: inject(TYPES.walkerMarkdownService),
|
|
10843
11177
|
heatMarkdownService: inject(TYPES.heatMarkdownService),
|
|
10844
11178
|
partialMarkdownService: inject(TYPES.partialMarkdownService),
|
|
11179
|
+
outlineMarkdownService: inject(TYPES.outlineMarkdownService),
|
|
10845
11180
|
};
|
|
10846
11181
|
const validationServices = {
|
|
10847
11182
|
exchangeValidationService: inject(TYPES.exchangeValidationService),
|
|
@@ -12508,6 +12843,83 @@ async function getMode() {
|
|
|
12508
12843
|
return bt ? "backtest" : "live";
|
|
12509
12844
|
}
|
|
12510
12845
|
|
|
12846
|
+
const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
|
|
12847
|
+
/**
|
|
12848
|
+
* Dumps signal data and LLM conversation history to markdown files.
|
|
12849
|
+
* Used by AI-powered strategies to save debug logs for analysis.
|
|
12850
|
+
*
|
|
12851
|
+
* Creates a directory structure with:
|
|
12852
|
+
* - 00_system_prompt.md - System messages and output summary
|
|
12853
|
+
* - XX_user_message.md - Each user message in separate file (numbered)
|
|
12854
|
+
* - XX_llm_output.md - Final LLM output with signal data
|
|
12855
|
+
*
|
|
12856
|
+
* Skips if directory already exists to avoid overwriting previous results.
|
|
12857
|
+
*
|
|
12858
|
+
* @param signalId - Unique identifier for the result (used as directory name, e.g., UUID)
|
|
12859
|
+
* @param history - Array of message models from LLM conversation
|
|
12860
|
+
* @param signal - Signal DTO returned by LLM (position, priceOpen, TP, SL, etc.)
|
|
12861
|
+
* @param outputDir - Output directory path (default: "./dump/strategy")
|
|
12862
|
+
* @returns Promise that resolves when all files are written
|
|
12863
|
+
*
|
|
12864
|
+
* @example
|
|
12865
|
+
* ```typescript
|
|
12866
|
+
* import { dumpSignal, getCandles } from "backtest-kit";
|
|
12867
|
+
* import { v4 as uuid } from "uuid";
|
|
12868
|
+
*
|
|
12869
|
+
* addStrategy({
|
|
12870
|
+
* strategyName: "llm-strategy",
|
|
12871
|
+
* interval: "5m",
|
|
12872
|
+
* getSignal: async (symbol) => {
|
|
12873
|
+
* const messages = [];
|
|
12874
|
+
*
|
|
12875
|
+
* // Build multi-timeframe analysis conversation
|
|
12876
|
+
* const candles1h = await getCandles(symbol, "1h", 24);
|
|
12877
|
+
* messages.push(
|
|
12878
|
+
* { role: "user", content: `Analyze 1h trend:\n${formatCandles(candles1h)}` },
|
|
12879
|
+
* { role: "assistant", content: "Trend analyzed" }
|
|
12880
|
+
* );
|
|
12881
|
+
*
|
|
12882
|
+
* const candles5m = await getCandles(symbol, "5m", 24);
|
|
12883
|
+
* messages.push(
|
|
12884
|
+
* { role: "user", content: `Analyze 5m structure:\n${formatCandles(candles5m)}` },
|
|
12885
|
+
* { role: "assistant", content: "Structure analyzed" }
|
|
12886
|
+
* );
|
|
12887
|
+
*
|
|
12888
|
+
* // Request signal
|
|
12889
|
+
* messages.push({
|
|
12890
|
+
* role: "user",
|
|
12891
|
+
* content: "Generate trading signal. Use position: 'wait' if uncertain."
|
|
12892
|
+
* });
|
|
12893
|
+
*
|
|
12894
|
+
* const resultId = uuid();
|
|
12895
|
+
* const signal = await llmRequest(messages);
|
|
12896
|
+
*
|
|
12897
|
+
* // Save conversation and result for debugging
|
|
12898
|
+
* await dumpSignal(resultId, messages, signal);
|
|
12899
|
+
*
|
|
12900
|
+
* return signal;
|
|
12901
|
+
* }
|
|
12902
|
+
* });
|
|
12903
|
+
*
|
|
12904
|
+
* // Creates: ./dump/strategy/{uuid}/00_system_prompt.md
|
|
12905
|
+
* // ./dump/strategy/{uuid}/01_user_message.md (1h analysis)
|
|
12906
|
+
* // ./dump/strategy/{uuid}/02_assistant_message.md
|
|
12907
|
+
* // ./dump/strategy/{uuid}/03_user_message.md (5m analysis)
|
|
12908
|
+
* // ./dump/strategy/{uuid}/04_assistant_message.md
|
|
12909
|
+
* // ./dump/strategy/{uuid}/05_user_message.md (signal request)
|
|
12910
|
+
* // ./dump/strategy/{uuid}/06_llm_output.md (final signal)
|
|
12911
|
+
* ```
|
|
12912
|
+
*/
|
|
12913
|
+
async function dumpSignal(signalId, history, signal, outputDir = "./dump/strategy") {
|
|
12914
|
+
backtest$1.loggerService.info(DUMP_SIGNAL_METHOD_NAME, {
|
|
12915
|
+
signalId,
|
|
12916
|
+
history,
|
|
12917
|
+
signal,
|
|
12918
|
+
outputDir,
|
|
12919
|
+
});
|
|
12920
|
+
return await backtest$1.outlineMarkdownService.dumpSignal(signalId, history, signal, outputDir);
|
|
12921
|
+
}
|
|
12922
|
+
|
|
12511
12923
|
const BACKTEST_METHOD_NAME_RUN = "BacktestUtils.run";
|
|
12512
12924
|
const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
|
|
12513
12925
|
const BACKTEST_METHOD_NAME_GET_REPORT = "BacktestUtils.getReport";
|
|
@@ -13976,6 +14388,7 @@ exports.addRisk = addRisk;
|
|
|
13976
14388
|
exports.addSizing = addSizing;
|
|
13977
14389
|
exports.addStrategy = addStrategy;
|
|
13978
14390
|
exports.addWalker = addWalker;
|
|
14391
|
+
exports.dumpSignal = dumpSignal;
|
|
13979
14392
|
exports.emitters = emitters;
|
|
13980
14393
|
exports.formatPrice = formatPrice;
|
|
13981
14394
|
exports.formatQuantity = formatQuantity;
|
package/build/index.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import fs, { mkdir, writeFile } from 'fs/promises';
|
|
|
5
5
|
import path, { join } from 'path';
|
|
6
6
|
import crypto from 'crypto';
|
|
7
7
|
import os from 'os';
|
|
8
|
+
import { promises } from 'fs';
|
|
8
9
|
|
|
9
10
|
const GLOBAL_CONFIG = {
|
|
10
11
|
/**
|
|
@@ -160,6 +161,7 @@ const markdownServices$1 = {
|
|
|
160
161
|
walkerMarkdownService: Symbol('walkerMarkdownService'),
|
|
161
162
|
heatMarkdownService: Symbol('heatMarkdownService'),
|
|
162
163
|
partialMarkdownService: Symbol('partialMarkdownService'),
|
|
164
|
+
outlineMarkdownService: Symbol('outlineMarkdownService'),
|
|
163
165
|
};
|
|
164
166
|
const validationServices$1 = {
|
|
165
167
|
exchangeValidationService: Symbol('exchangeValidationService'),
|
|
@@ -7260,6 +7262,118 @@ function formatMetric(value) {
|
|
|
7260
7262
|
}
|
|
7261
7263
|
return value.toFixed(2);
|
|
7262
7264
|
}
|
|
7265
|
+
/**
|
|
7266
|
+
* Creates strategy comparison columns based on metric name.
|
|
7267
|
+
* Dynamically builds column configuration with metric-specific header.
|
|
7268
|
+
*
|
|
7269
|
+
* @param metric - Metric being optimized
|
|
7270
|
+
* @returns Array of column configurations for strategy comparison table
|
|
7271
|
+
*/
|
|
7272
|
+
function createStrategyColumns(metric) {
|
|
7273
|
+
return [
|
|
7274
|
+
{
|
|
7275
|
+
key: "rank",
|
|
7276
|
+
label: "Rank",
|
|
7277
|
+
format: (data, index) => `${index + 1}`,
|
|
7278
|
+
},
|
|
7279
|
+
{
|
|
7280
|
+
key: "strategy",
|
|
7281
|
+
label: "Strategy",
|
|
7282
|
+
format: (data) => data.strategyName,
|
|
7283
|
+
},
|
|
7284
|
+
{
|
|
7285
|
+
key: "metric",
|
|
7286
|
+
label: metric,
|
|
7287
|
+
format: (data) => formatMetric(data.metricValue),
|
|
7288
|
+
},
|
|
7289
|
+
{
|
|
7290
|
+
key: "totalSignals",
|
|
7291
|
+
label: "Total Signals",
|
|
7292
|
+
format: (data) => `${data.stats.totalSignals}`,
|
|
7293
|
+
},
|
|
7294
|
+
{
|
|
7295
|
+
key: "winRate",
|
|
7296
|
+
label: "Win Rate",
|
|
7297
|
+
format: (data) => data.stats.winRate !== null
|
|
7298
|
+
? `${data.stats.winRate.toFixed(2)}%`
|
|
7299
|
+
: "N/A",
|
|
7300
|
+
},
|
|
7301
|
+
{
|
|
7302
|
+
key: "avgPnl",
|
|
7303
|
+
label: "Avg PNL",
|
|
7304
|
+
format: (data) => data.stats.avgPnl !== null
|
|
7305
|
+
? `${data.stats.avgPnl > 0 ? "+" : ""}${data.stats.avgPnl.toFixed(2)}%`
|
|
7306
|
+
: "N/A",
|
|
7307
|
+
},
|
|
7308
|
+
{
|
|
7309
|
+
key: "totalPnl",
|
|
7310
|
+
label: "Total PNL",
|
|
7311
|
+
format: (data) => data.stats.totalPnl !== null
|
|
7312
|
+
? `${data.stats.totalPnl > 0 ? "+" : ""}${data.stats.totalPnl.toFixed(2)}%`
|
|
7313
|
+
: "N/A",
|
|
7314
|
+
},
|
|
7315
|
+
{
|
|
7316
|
+
key: "sharpeRatio",
|
|
7317
|
+
label: "Sharpe Ratio",
|
|
7318
|
+
format: (data) => data.stats.sharpeRatio !== null
|
|
7319
|
+
? `${data.stats.sharpeRatio.toFixed(3)}`
|
|
7320
|
+
: "N/A",
|
|
7321
|
+
},
|
|
7322
|
+
{
|
|
7323
|
+
key: "stdDev",
|
|
7324
|
+
label: "Std Dev",
|
|
7325
|
+
format: (data) => data.stats.stdDev !== null
|
|
7326
|
+
? `${data.stats.stdDev.toFixed(3)}%`
|
|
7327
|
+
: "N/A",
|
|
7328
|
+
},
|
|
7329
|
+
];
|
|
7330
|
+
}
|
|
7331
|
+
/**
|
|
7332
|
+
* Column configuration for PNL table.
|
|
7333
|
+
* Defines all columns for displaying closed signals across strategies.
|
|
7334
|
+
*/
|
|
7335
|
+
const pnlColumns = [
|
|
7336
|
+
{
|
|
7337
|
+
key: "strategy",
|
|
7338
|
+
label: "Strategy",
|
|
7339
|
+
format: (data) => data.strategyName,
|
|
7340
|
+
},
|
|
7341
|
+
{
|
|
7342
|
+
key: "signalId",
|
|
7343
|
+
label: "Signal ID",
|
|
7344
|
+
format: (data) => data.signalId,
|
|
7345
|
+
},
|
|
7346
|
+
{
|
|
7347
|
+
key: "symbol",
|
|
7348
|
+
label: "Symbol",
|
|
7349
|
+
format: (data) => data.symbol,
|
|
7350
|
+
},
|
|
7351
|
+
{
|
|
7352
|
+
key: "position",
|
|
7353
|
+
label: "Position",
|
|
7354
|
+
format: (data) => data.position.toUpperCase(),
|
|
7355
|
+
},
|
|
7356
|
+
{
|
|
7357
|
+
key: "pnl",
|
|
7358
|
+
label: "PNL (net)",
|
|
7359
|
+
format: (data) => `${data.pnl > 0 ? "+" : ""}${data.pnl.toFixed(2)}%`,
|
|
7360
|
+
},
|
|
7361
|
+
{
|
|
7362
|
+
key: "closeReason",
|
|
7363
|
+
label: "Close Reason",
|
|
7364
|
+
format: (data) => data.closeReason,
|
|
7365
|
+
},
|
|
7366
|
+
{
|
|
7367
|
+
key: "openTime",
|
|
7368
|
+
label: "Open Time",
|
|
7369
|
+
format: (data) => new Date(data.openTime).toISOString(),
|
|
7370
|
+
},
|
|
7371
|
+
{
|
|
7372
|
+
key: "closeTime",
|
|
7373
|
+
label: "Close Time",
|
|
7374
|
+
format: (data) => new Date(data.closeTime).toISOString(),
|
|
7375
|
+
},
|
|
7376
|
+
];
|
|
7263
7377
|
/**
|
|
7264
7378
|
* Storage class for accumulating walker results.
|
|
7265
7379
|
* Maintains a list of all strategy results and provides methods to generate reports.
|
|
@@ -7272,9 +7386,12 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
7272
7386
|
this._bestStats = null;
|
|
7273
7387
|
this._bestMetric = null;
|
|
7274
7388
|
this._bestStrategy = null;
|
|
7389
|
+
/** All strategy results for comparison table */
|
|
7390
|
+
this._strategyResults = [];
|
|
7275
7391
|
}
|
|
7276
7392
|
/**
|
|
7277
7393
|
* Adds a strategy result to the storage.
|
|
7394
|
+
* Updates best strategy tracking and accumulates result for comparison table.
|
|
7278
7395
|
*
|
|
7279
7396
|
* @param data - Walker contract with strategy result
|
|
7280
7397
|
*/
|
|
@@ -7288,6 +7405,12 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
7288
7405
|
if (data.strategyName === data.bestStrategy) {
|
|
7289
7406
|
this._bestStats = data.stats;
|
|
7290
7407
|
}
|
|
7408
|
+
// Add strategy result to comparison list
|
|
7409
|
+
this._strategyResults.push({
|
|
7410
|
+
strategyName: data.strategyName,
|
|
7411
|
+
stats: data.stats,
|
|
7412
|
+
metricValue: data.metricValue,
|
|
7413
|
+
});
|
|
7291
7414
|
}
|
|
7292
7415
|
/**
|
|
7293
7416
|
* Calculates walker results from strategy results.
|
|
@@ -7312,10 +7435,79 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
7312
7435
|
bestStrategy: this._bestStrategy,
|
|
7313
7436
|
bestMetric: this._bestMetric,
|
|
7314
7437
|
bestStats: this._bestStats,
|
|
7438
|
+
strategyResults: this._strategyResults,
|
|
7315
7439
|
};
|
|
7316
7440
|
}
|
|
7441
|
+
/**
|
|
7442
|
+
* Generates comparison table for top N strategies (View).
|
|
7443
|
+
* Sorts strategies by metric value and formats as markdown table.
|
|
7444
|
+
*
|
|
7445
|
+
* @param metric - Metric being optimized
|
|
7446
|
+
* @param topN - Number of top strategies to include (default: 10)
|
|
7447
|
+
* @returns Markdown formatted comparison table
|
|
7448
|
+
*/
|
|
7449
|
+
getComparisonTable(metric, topN = 10) {
|
|
7450
|
+
if (this._strategyResults.length === 0) {
|
|
7451
|
+
return "No strategy results available.";
|
|
7452
|
+
}
|
|
7453
|
+
// Sort strategies by metric value (descending)
|
|
7454
|
+
const sortedResults = [...this._strategyResults].sort((a, b) => {
|
|
7455
|
+
const aValue = a.metricValue ?? -Infinity;
|
|
7456
|
+
const bValue = b.metricValue ?? -Infinity;
|
|
7457
|
+
return bValue - aValue;
|
|
7458
|
+
});
|
|
7459
|
+
// Take top N strategies
|
|
7460
|
+
const topStrategies = sortedResults.slice(0, topN);
|
|
7461
|
+
// Get columns configuration
|
|
7462
|
+
const columns = createStrategyColumns(metric);
|
|
7463
|
+
// Build table header
|
|
7464
|
+
const header = columns.map((col) => col.label);
|
|
7465
|
+
const separator = columns.map(() => "---");
|
|
7466
|
+
// Build table rows
|
|
7467
|
+
const rows = topStrategies.map((result, index) => columns.map((col) => col.format(result, index)));
|
|
7468
|
+
const tableData = [header, separator, ...rows];
|
|
7469
|
+
return str.newline(tableData.map((row) => `| ${row.join(" | ")} |`));
|
|
7470
|
+
}
|
|
7471
|
+
/**
|
|
7472
|
+
* Generates PNL table showing all closed signals across all strategies (View).
|
|
7473
|
+
* Collects all signals from all strategies and formats as markdown table.
|
|
7474
|
+
*
|
|
7475
|
+
* @returns Markdown formatted PNL table
|
|
7476
|
+
*/
|
|
7477
|
+
getPnlTable() {
|
|
7478
|
+
if (this._strategyResults.length === 0) {
|
|
7479
|
+
return "No strategy results available.";
|
|
7480
|
+
}
|
|
7481
|
+
// Collect all closed signals from all strategies
|
|
7482
|
+
const allSignals = [];
|
|
7483
|
+
for (const result of this._strategyResults) {
|
|
7484
|
+
for (const signal of result.stats.signalList) {
|
|
7485
|
+
allSignals.push({
|
|
7486
|
+
strategyName: result.strategyName,
|
|
7487
|
+
signalId: signal.signal.id,
|
|
7488
|
+
symbol: signal.signal.symbol,
|
|
7489
|
+
position: signal.signal.position,
|
|
7490
|
+
pnl: signal.pnl.pnlPercentage,
|
|
7491
|
+
closeReason: signal.closeReason,
|
|
7492
|
+
openTime: signal.signal.pendingAt,
|
|
7493
|
+
closeTime: signal.closeTimestamp,
|
|
7494
|
+
});
|
|
7495
|
+
}
|
|
7496
|
+
}
|
|
7497
|
+
if (allSignals.length === 0) {
|
|
7498
|
+
return "No closed signals available.";
|
|
7499
|
+
}
|
|
7500
|
+
// Build table header
|
|
7501
|
+
const header = pnlColumns.map((col) => col.label);
|
|
7502
|
+
const separator = pnlColumns.map(() => "---");
|
|
7503
|
+
// Build table rows
|
|
7504
|
+
const rows = allSignals.map((signal) => pnlColumns.map((col) => col.format(signal)));
|
|
7505
|
+
const tableData = [header, separator, ...rows];
|
|
7506
|
+
return str.newline(tableData.map((row) => `| ${row.join(" | ")} |`));
|
|
7507
|
+
}
|
|
7317
7508
|
/**
|
|
7318
7509
|
* Generates markdown report with all strategy results (View).
|
|
7510
|
+
* Includes best strategy summary, comparison table, and PNL table.
|
|
7319
7511
|
*
|
|
7320
7512
|
* @param symbol - Trading symbol
|
|
7321
7513
|
* @param metric - Metric being optimized
|
|
@@ -7324,7 +7516,9 @@ let ReportStorage$1 = class ReportStorage {
|
|
|
7324
7516
|
*/
|
|
7325
7517
|
async getReport(symbol, metric, context) {
|
|
7326
7518
|
const results = await this.getData(symbol, metric, context);
|
|
7327
|
-
|
|
7519
|
+
// Get total signals for best strategy
|
|
7520
|
+
const bestStrategySignals = results.bestStats?.totalSignals ?? 0;
|
|
7521
|
+
return str.newline(`# Walker Comparison Report: ${results.walkerName}`, "", `**Symbol:** ${results.symbol}`, `**Exchange:** ${results.exchangeName}`, `**Frame:** ${results.frameName}`, `**Optimization Metric:** ${results.metric}`, `**Strategies Tested:** ${results.totalStrategies}`, "", `## Best Strategy: ${results.bestStrategy}`, "", `**Best ${results.metric}:** ${formatMetric(results.bestMetric)}`, `**Total Signals:** ${bestStrategySignals}`, "", "## Top Strategies Comparison", "", this.getComparisonTable(metric, 10), "", "## All Signals (PNL Table)", "", this.getPnlTable(), "", "**Note:** Higher values are better for all metrics except Standard Deviation (lower is better).");
|
|
7328
7522
|
}
|
|
7329
7523
|
/**
|
|
7330
7524
|
* Saves walker report to disk.
|
|
@@ -10712,6 +10906,145 @@ class PartialGlobalService {
|
|
|
10712
10906
|
}
|
|
10713
10907
|
}
|
|
10714
10908
|
|
|
10909
|
+
/**
|
|
10910
|
+
* Warning threshold for message size in kilobytes.
|
|
10911
|
+
* Messages exceeding this size trigger console warnings.
|
|
10912
|
+
*/
|
|
10913
|
+
const WARN_KB = 100;
|
|
10914
|
+
/**
|
|
10915
|
+
* Internal function for dumping signal data to markdown files.
|
|
10916
|
+
* Creates a directory structure with system prompts, user messages, and LLM output.
|
|
10917
|
+
*
|
|
10918
|
+
* @param signalId - Unique identifier for the result
|
|
10919
|
+
* @param history - Array of message models from LLM conversation
|
|
10920
|
+
* @param signal - Signal DTO with trade parameters
|
|
10921
|
+
* @param outputDir - Output directory path (default: "./dump/strategy")
|
|
10922
|
+
* @returns Promise that resolves when all files are written
|
|
10923
|
+
*/
|
|
10924
|
+
const DUMP_SIGNAL_FN = async (signalId, history, signal, outputDir = "./dump/strategy") => {
|
|
10925
|
+
// Extract system messages and system reminders from existing data
|
|
10926
|
+
const systemMessages = history.filter((m) => m.role === "system");
|
|
10927
|
+
const userMessages = history.filter((m) => m.role === "user");
|
|
10928
|
+
const subfolderPath = path.join(outputDir, String(signalId));
|
|
10929
|
+
try {
|
|
10930
|
+
await promises.access(subfolderPath);
|
|
10931
|
+
return;
|
|
10932
|
+
}
|
|
10933
|
+
catch {
|
|
10934
|
+
await promises.mkdir(subfolderPath, { recursive: true });
|
|
10935
|
+
}
|
|
10936
|
+
{
|
|
10937
|
+
let summary = "# Outline Result Summary\n";
|
|
10938
|
+
{
|
|
10939
|
+
summary += "\n";
|
|
10940
|
+
summary += `**ResultId**: ${String(signalId)}\n`;
|
|
10941
|
+
summary += "\n";
|
|
10942
|
+
}
|
|
10943
|
+
if (signal) {
|
|
10944
|
+
summary += "## Output Data\n\n";
|
|
10945
|
+
summary += "```json\n";
|
|
10946
|
+
summary += JSON.stringify(signal, null, 2);
|
|
10947
|
+
summary += "\n```\n\n";
|
|
10948
|
+
}
|
|
10949
|
+
// Add system messages to summary
|
|
10950
|
+
if (systemMessages.length > 0) {
|
|
10951
|
+
summary += "## System Messages\n\n";
|
|
10952
|
+
systemMessages.forEach((msg, idx) => {
|
|
10953
|
+
summary += `### System Message ${idx + 1}\n\n`;
|
|
10954
|
+
summary += msg.content;
|
|
10955
|
+
summary += "\n";
|
|
10956
|
+
});
|
|
10957
|
+
}
|
|
10958
|
+
const summaryFile = path.join(subfolderPath, "00_system_prompt.md");
|
|
10959
|
+
await promises.writeFile(summaryFile, summary, "utf8");
|
|
10960
|
+
}
|
|
10961
|
+
{
|
|
10962
|
+
await Promise.all(Array.from(userMessages.entries()).map(async ([idx, message]) => {
|
|
10963
|
+
const messageNum = String(idx + 1).padStart(2, "0");
|
|
10964
|
+
const contentFileName = `${messageNum}_user_message.md`;
|
|
10965
|
+
const contentFilePath = path.join(subfolderPath, contentFileName);
|
|
10966
|
+
{
|
|
10967
|
+
const messageSizeBytes = Buffer.byteLength(message.content, "utf8");
|
|
10968
|
+
const messageSizeKb = Math.floor(messageSizeBytes / 1024);
|
|
10969
|
+
if (messageSizeKb > WARN_KB) {
|
|
10970
|
+
console.warn(`User message ${idx + 1} is ${messageSizeBytes} bytes (${messageSizeKb}kb), which exceeds warning limit`);
|
|
10971
|
+
}
|
|
10972
|
+
}
|
|
10973
|
+
let content = `# User Input ${idx + 1}\n\n`;
|
|
10974
|
+
content += `**ResultId**: ${String(signalId)}\n\n`;
|
|
10975
|
+
content += message.content;
|
|
10976
|
+
content += "\n";
|
|
10977
|
+
await promises.writeFile(contentFilePath, content, "utf8");
|
|
10978
|
+
}));
|
|
10979
|
+
}
|
|
10980
|
+
{
|
|
10981
|
+
const messageNum = String(userMessages.length + 1).padStart(2, "0");
|
|
10982
|
+
const contentFileName = `${messageNum}_llm_output.md`;
|
|
10983
|
+
const contentFilePath = path.join(subfolderPath, contentFileName);
|
|
10984
|
+
let content = "# Full Outline Result\n\n";
|
|
10985
|
+
content += `**ResultId**: ${String(signalId)}\n\n`;
|
|
10986
|
+
if (signal) {
|
|
10987
|
+
content += "## Output Data\n\n";
|
|
10988
|
+
content += "```json\n";
|
|
10989
|
+
content += JSON.stringify(signal, null, 2);
|
|
10990
|
+
content += "\n```\n";
|
|
10991
|
+
}
|
|
10992
|
+
await promises.writeFile(contentFilePath, content, "utf8");
|
|
10993
|
+
}
|
|
10994
|
+
};
|
|
10995
|
+
/**
|
|
10996
|
+
* Service for generating markdown documentation from LLM outline results.
|
|
10997
|
+
* Used by AI Strategy Optimizer to save debug logs and conversation history.
|
|
10998
|
+
*
|
|
10999
|
+
* Creates directory structure:
|
|
11000
|
+
* - ./dump/strategy/{signalId}/00_system_prompt.md - System messages and output data
|
|
11001
|
+
* - ./dump/strategy/{signalId}/01_user_message.md - First user input
|
|
11002
|
+
* - ./dump/strategy/{signalId}/02_user_message.md - Second user input
|
|
11003
|
+
* - ./dump/strategy/{signalId}/XX_llm_output.md - Final LLM output
|
|
11004
|
+
*/
|
|
11005
|
+
class OutlineMarkdownService {
|
|
11006
|
+
constructor() {
|
|
11007
|
+
/** Logger service injected via DI */
|
|
11008
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
11009
|
+
/**
|
|
11010
|
+
* Dumps signal data and conversation history to markdown files.
|
|
11011
|
+
* Skips if directory already exists to avoid overwriting previous results.
|
|
11012
|
+
*
|
|
11013
|
+
* Generated files:
|
|
11014
|
+
* - 00_system_prompt.md - System messages and output summary
|
|
11015
|
+
* - XX_user_message.md - Each user message in separate file (numbered)
|
|
11016
|
+
* - XX_llm_output.md - Final LLM output with signal data
|
|
11017
|
+
*
|
|
11018
|
+
* @param signalId - Unique identifier for the result (used as directory name)
|
|
11019
|
+
* @param history - Array of message models from LLM conversation
|
|
11020
|
+
* @param signal - Signal DTO with trade parameters (priceOpen, TP, SL, etc.)
|
|
11021
|
+
* @param outputDir - Output directory path (default: "./dump/strategy")
|
|
11022
|
+
* @returns Promise that resolves when all files are written
|
|
11023
|
+
*
|
|
11024
|
+
* @example
|
|
11025
|
+
* ```typescript
|
|
11026
|
+
* await outlineService.dumpSignal(
|
|
11027
|
+
* "strategy-1",
|
|
11028
|
+
* conversationHistory,
|
|
11029
|
+
* { position: "long", priceTakeProfit: 51000, priceStopLoss: 49000, minuteEstimatedTime: 60 }
|
|
11030
|
+
* );
|
|
11031
|
+
* // Creates: ./dump/strategy/strategy-1/00_system_prompt.md
|
|
11032
|
+
* // ./dump/strategy/strategy-1/01_user_message.md
|
|
11033
|
+
* // ./dump/strategy/strategy-1/02_llm_output.md
|
|
11034
|
+
* ```
|
|
11035
|
+
*/
|
|
11036
|
+
this.dumpSignal = async (signalId, history, signal, outputDir = "./dump/strategy") => {
|
|
11037
|
+
this.loggerService.log("outlineMarkdownService dumpSignal", {
|
|
11038
|
+
signalId,
|
|
11039
|
+
history,
|
|
11040
|
+
signal,
|
|
11041
|
+
outputDir,
|
|
11042
|
+
});
|
|
11043
|
+
return await DUMP_SIGNAL_FN(signalId, history, signal, outputDir);
|
|
11044
|
+
};
|
|
11045
|
+
}
|
|
11046
|
+
}
|
|
11047
|
+
|
|
10715
11048
|
{
|
|
10716
11049
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
10717
11050
|
}
|
|
@@ -10769,6 +11102,7 @@ class PartialGlobalService {
|
|
|
10769
11102
|
provide(TYPES.walkerMarkdownService, () => new WalkerMarkdownService());
|
|
10770
11103
|
provide(TYPES.heatMarkdownService, () => new HeatMarkdownService());
|
|
10771
11104
|
provide(TYPES.partialMarkdownService, () => new PartialMarkdownService());
|
|
11105
|
+
provide(TYPES.outlineMarkdownService, () => new OutlineMarkdownService());
|
|
10772
11106
|
}
|
|
10773
11107
|
{
|
|
10774
11108
|
provide(TYPES.exchangeValidationService, () => new ExchangeValidationService());
|
|
@@ -10840,6 +11174,7 @@ const markdownServices = {
|
|
|
10840
11174
|
walkerMarkdownService: inject(TYPES.walkerMarkdownService),
|
|
10841
11175
|
heatMarkdownService: inject(TYPES.heatMarkdownService),
|
|
10842
11176
|
partialMarkdownService: inject(TYPES.partialMarkdownService),
|
|
11177
|
+
outlineMarkdownService: inject(TYPES.outlineMarkdownService),
|
|
10843
11178
|
};
|
|
10844
11179
|
const validationServices = {
|
|
10845
11180
|
exchangeValidationService: inject(TYPES.exchangeValidationService),
|
|
@@ -12506,6 +12841,83 @@ async function getMode() {
|
|
|
12506
12841
|
return bt ? "backtest" : "live";
|
|
12507
12842
|
}
|
|
12508
12843
|
|
|
12844
|
+
const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
|
|
12845
|
+
/**
|
|
12846
|
+
* Dumps signal data and LLM conversation history to markdown files.
|
|
12847
|
+
* Used by AI-powered strategies to save debug logs for analysis.
|
|
12848
|
+
*
|
|
12849
|
+
* Creates a directory structure with:
|
|
12850
|
+
* - 00_system_prompt.md - System messages and output summary
|
|
12851
|
+
* - XX_user_message.md - Each user message in separate file (numbered)
|
|
12852
|
+
* - XX_llm_output.md - Final LLM output with signal data
|
|
12853
|
+
*
|
|
12854
|
+
* Skips if directory already exists to avoid overwriting previous results.
|
|
12855
|
+
*
|
|
12856
|
+
* @param signalId - Unique identifier for the result (used as directory name, e.g., UUID)
|
|
12857
|
+
* @param history - Array of message models from LLM conversation
|
|
12858
|
+
* @param signal - Signal DTO returned by LLM (position, priceOpen, TP, SL, etc.)
|
|
12859
|
+
* @param outputDir - Output directory path (default: "./dump/strategy")
|
|
12860
|
+
* @returns Promise that resolves when all files are written
|
|
12861
|
+
*
|
|
12862
|
+
* @example
|
|
12863
|
+
* ```typescript
|
|
12864
|
+
* import { dumpSignal, getCandles } from "backtest-kit";
|
|
12865
|
+
* import { v4 as uuid } from "uuid";
|
|
12866
|
+
*
|
|
12867
|
+
* addStrategy({
|
|
12868
|
+
* strategyName: "llm-strategy",
|
|
12869
|
+
* interval: "5m",
|
|
12870
|
+
* getSignal: async (symbol) => {
|
|
12871
|
+
* const messages = [];
|
|
12872
|
+
*
|
|
12873
|
+
* // Build multi-timeframe analysis conversation
|
|
12874
|
+
* const candles1h = await getCandles(symbol, "1h", 24);
|
|
12875
|
+
* messages.push(
|
|
12876
|
+
* { role: "user", content: `Analyze 1h trend:\n${formatCandles(candles1h)}` },
|
|
12877
|
+
* { role: "assistant", content: "Trend analyzed" }
|
|
12878
|
+
* );
|
|
12879
|
+
*
|
|
12880
|
+
* const candles5m = await getCandles(symbol, "5m", 24);
|
|
12881
|
+
* messages.push(
|
|
12882
|
+
* { role: "user", content: `Analyze 5m structure:\n${formatCandles(candles5m)}` },
|
|
12883
|
+
* { role: "assistant", content: "Structure analyzed" }
|
|
12884
|
+
* );
|
|
12885
|
+
*
|
|
12886
|
+
* // Request signal
|
|
12887
|
+
* messages.push({
|
|
12888
|
+
* role: "user",
|
|
12889
|
+
* content: "Generate trading signal. Use position: 'wait' if uncertain."
|
|
12890
|
+
* });
|
|
12891
|
+
*
|
|
12892
|
+
* const resultId = uuid();
|
|
12893
|
+
* const signal = await llmRequest(messages);
|
|
12894
|
+
*
|
|
12895
|
+
* // Save conversation and result for debugging
|
|
12896
|
+
* await dumpSignal(resultId, messages, signal);
|
|
12897
|
+
*
|
|
12898
|
+
* return signal;
|
|
12899
|
+
* }
|
|
12900
|
+
* });
|
|
12901
|
+
*
|
|
12902
|
+
* // Creates: ./dump/strategy/{uuid}/00_system_prompt.md
|
|
12903
|
+
* // ./dump/strategy/{uuid}/01_user_message.md (1h analysis)
|
|
12904
|
+
* // ./dump/strategy/{uuid}/02_assistant_message.md
|
|
12905
|
+
* // ./dump/strategy/{uuid}/03_user_message.md (5m analysis)
|
|
12906
|
+
* // ./dump/strategy/{uuid}/04_assistant_message.md
|
|
12907
|
+
* // ./dump/strategy/{uuid}/05_user_message.md (signal request)
|
|
12908
|
+
* // ./dump/strategy/{uuid}/06_llm_output.md (final signal)
|
|
12909
|
+
* ```
|
|
12910
|
+
*/
|
|
12911
|
+
async function dumpSignal(signalId, history, signal, outputDir = "./dump/strategy") {
|
|
12912
|
+
backtest$1.loggerService.info(DUMP_SIGNAL_METHOD_NAME, {
|
|
12913
|
+
signalId,
|
|
12914
|
+
history,
|
|
12915
|
+
signal,
|
|
12916
|
+
outputDir,
|
|
12917
|
+
});
|
|
12918
|
+
return await backtest$1.outlineMarkdownService.dumpSignal(signalId, history, signal, outputDir);
|
|
12919
|
+
}
|
|
12920
|
+
|
|
12509
12921
|
const BACKTEST_METHOD_NAME_RUN = "BacktestUtils.run";
|
|
12510
12922
|
const BACKTEST_METHOD_NAME_BACKGROUND = "BacktestUtils.background";
|
|
12511
12923
|
const BACKTEST_METHOD_NAME_GET_REPORT = "BacktestUtils.getReport";
|
|
@@ -13950,4 +14362,4 @@ class ConstantUtils {
|
|
|
13950
14362
|
*/
|
|
13951
14363
|
const Constant = new ConstantUtils();
|
|
13952
14364
|
|
|
13953
|
-
export { Backtest, Constant, ExecutionContextService, Heat, Live, MethodContextService, Optimizer, Partial, Performance, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Schedule, Walker, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
|
|
14365
|
+
export { Backtest, Constant, ExecutionContextService, Heat, Live, MethodContextService, Optimizer, Partial, Performance, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, Schedule, Walker, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, dumpSignal, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
|
package/package.json
CHANGED
package/types.d.ts
CHANGED
|
@@ -3616,6 +3616,74 @@ declare function getDate(): Promise<Date>;
|
|
|
3616
3616
|
*/
|
|
3617
3617
|
declare function getMode(): Promise<"backtest" | "live">;
|
|
3618
3618
|
|
|
3619
|
+
/**
|
|
3620
|
+
* Dumps signal data and LLM conversation history to markdown files.
|
|
3621
|
+
* Used by AI-powered strategies to save debug logs for analysis.
|
|
3622
|
+
*
|
|
3623
|
+
* Creates a directory structure with:
|
|
3624
|
+
* - 00_system_prompt.md - System messages and output summary
|
|
3625
|
+
* - XX_user_message.md - Each user message in separate file (numbered)
|
|
3626
|
+
* - XX_llm_output.md - Final LLM output with signal data
|
|
3627
|
+
*
|
|
3628
|
+
* Skips if directory already exists to avoid overwriting previous results.
|
|
3629
|
+
*
|
|
3630
|
+
* @param signalId - Unique identifier for the result (used as directory name, e.g., UUID)
|
|
3631
|
+
* @param history - Array of message models from LLM conversation
|
|
3632
|
+
* @param signal - Signal DTO returned by LLM (position, priceOpen, TP, SL, etc.)
|
|
3633
|
+
* @param outputDir - Output directory path (default: "./dump/strategy")
|
|
3634
|
+
* @returns Promise that resolves when all files are written
|
|
3635
|
+
*
|
|
3636
|
+
* @example
|
|
3637
|
+
* ```typescript
|
|
3638
|
+
* import { dumpSignal, getCandles } from "backtest-kit";
|
|
3639
|
+
* import { v4 as uuid } from "uuid";
|
|
3640
|
+
*
|
|
3641
|
+
* addStrategy({
|
|
3642
|
+
* strategyName: "llm-strategy",
|
|
3643
|
+
* interval: "5m",
|
|
3644
|
+
* getSignal: async (symbol) => {
|
|
3645
|
+
* const messages = [];
|
|
3646
|
+
*
|
|
3647
|
+
* // Build multi-timeframe analysis conversation
|
|
3648
|
+
* const candles1h = await getCandles(symbol, "1h", 24);
|
|
3649
|
+
* messages.push(
|
|
3650
|
+
* { role: "user", content: `Analyze 1h trend:\n${formatCandles(candles1h)}` },
|
|
3651
|
+
* { role: "assistant", content: "Trend analyzed" }
|
|
3652
|
+
* );
|
|
3653
|
+
*
|
|
3654
|
+
* const candles5m = await getCandles(symbol, "5m", 24);
|
|
3655
|
+
* messages.push(
|
|
3656
|
+
* { role: "user", content: `Analyze 5m structure:\n${formatCandles(candles5m)}` },
|
|
3657
|
+
* { role: "assistant", content: "Structure analyzed" }
|
|
3658
|
+
* );
|
|
3659
|
+
*
|
|
3660
|
+
* // Request signal
|
|
3661
|
+
* messages.push({
|
|
3662
|
+
* role: "user",
|
|
3663
|
+
* content: "Generate trading signal. Use position: 'wait' if uncertain."
|
|
3664
|
+
* });
|
|
3665
|
+
*
|
|
3666
|
+
* const resultId = uuid();
|
|
3667
|
+
* const signal = await llmRequest(messages);
|
|
3668
|
+
*
|
|
3669
|
+
* // Save conversation and result for debugging
|
|
3670
|
+
* await dumpSignal(resultId, messages, signal);
|
|
3671
|
+
*
|
|
3672
|
+
* return signal;
|
|
3673
|
+
* }
|
|
3674
|
+
* });
|
|
3675
|
+
*
|
|
3676
|
+
* // Creates: ./dump/strategy/{uuid}/00_system_prompt.md
|
|
3677
|
+
* // ./dump/strategy/{uuid}/01_user_message.md (1h analysis)
|
|
3678
|
+
* // ./dump/strategy/{uuid}/02_assistant_message.md
|
|
3679
|
+
* // ./dump/strategy/{uuid}/03_user_message.md (5m analysis)
|
|
3680
|
+
* // ./dump/strategy/{uuid}/04_assistant_message.md
|
|
3681
|
+
* // ./dump/strategy/{uuid}/05_user_message.md (signal request)
|
|
3682
|
+
* // ./dump/strategy/{uuid}/06_llm_output.md (final signal)
|
|
3683
|
+
* ```
|
|
3684
|
+
*/
|
|
3685
|
+
declare function dumpSignal(signalId: string | number, history: MessageModel[], signal: ISignalDto, outputDir?: string): Promise<void>;
|
|
3686
|
+
|
|
3619
3687
|
/**
|
|
3620
3688
|
* Portfolio heatmap statistics for a single symbol.
|
|
3621
3689
|
* Aggregated metrics across all strategies for one trading pair.
|
|
@@ -4258,8 +4326,24 @@ declare class PerformanceMarkdownService {
|
|
|
4258
4326
|
* Alias for walker statistics result interface.
|
|
4259
4327
|
* Used for clarity in markdown service context.
|
|
4260
4328
|
*
|
|
4329
|
+
* Extends IWalkerResults with additional strategy comparison data.
|
|
4261
4330
|
*/
|
|
4262
|
-
|
|
4331
|
+
interface WalkerStatistics extends IWalkerResults {
|
|
4332
|
+
/** Array of all strategy results for comparison and analysis */
|
|
4333
|
+
strategyResults: IStrategyResult[];
|
|
4334
|
+
}
|
|
4335
|
+
/**
|
|
4336
|
+
* Strategy result entry for comparison table.
|
|
4337
|
+
* Contains strategy name, full statistics, and metric value for ranking.
|
|
4338
|
+
*/
|
|
4339
|
+
interface IStrategyResult {
|
|
4340
|
+
/** Strategy name */
|
|
4341
|
+
strategyName: StrategyName;
|
|
4342
|
+
/** Complete backtest statistics for this strategy */
|
|
4343
|
+
stats: BacktestStatistics;
|
|
4344
|
+
/** Value of the optimization metric (null if invalid) */
|
|
4345
|
+
metricValue: number | null;
|
|
4346
|
+
}
|
|
4263
4347
|
/**
|
|
4264
4348
|
* Service for generating and saving walker markdown reports.
|
|
4265
4349
|
*
|
|
@@ -8645,6 +8729,54 @@ declare class PartialGlobalService {
|
|
|
8645
8729
|
clear: (symbol: string, data: ISignalRow, priceClose: number) => Promise<void>;
|
|
8646
8730
|
}
|
|
8647
8731
|
|
|
8732
|
+
/**
|
|
8733
|
+
* Unique identifier for outline result.
|
|
8734
|
+
* Can be string or number for flexible ID formats.
|
|
8735
|
+
*/
|
|
8736
|
+
type ResultId = string | number;
|
|
8737
|
+
/**
|
|
8738
|
+
* Service for generating markdown documentation from LLM outline results.
|
|
8739
|
+
* Used by AI Strategy Optimizer to save debug logs and conversation history.
|
|
8740
|
+
*
|
|
8741
|
+
* Creates directory structure:
|
|
8742
|
+
* - ./dump/strategy/{signalId}/00_system_prompt.md - System messages and output data
|
|
8743
|
+
* - ./dump/strategy/{signalId}/01_user_message.md - First user input
|
|
8744
|
+
* - ./dump/strategy/{signalId}/02_user_message.md - Second user input
|
|
8745
|
+
* - ./dump/strategy/{signalId}/XX_llm_output.md - Final LLM output
|
|
8746
|
+
*/
|
|
8747
|
+
declare class OutlineMarkdownService {
|
|
8748
|
+
/** Logger service injected via DI */
|
|
8749
|
+
private readonly loggerService;
|
|
8750
|
+
/**
|
|
8751
|
+
* Dumps signal data and conversation history to markdown files.
|
|
8752
|
+
* Skips if directory already exists to avoid overwriting previous results.
|
|
8753
|
+
*
|
|
8754
|
+
* Generated files:
|
|
8755
|
+
* - 00_system_prompt.md - System messages and output summary
|
|
8756
|
+
* - XX_user_message.md - Each user message in separate file (numbered)
|
|
8757
|
+
* - XX_llm_output.md - Final LLM output with signal data
|
|
8758
|
+
*
|
|
8759
|
+
* @param signalId - Unique identifier for the result (used as directory name)
|
|
8760
|
+
* @param history - Array of message models from LLM conversation
|
|
8761
|
+
* @param signal - Signal DTO with trade parameters (priceOpen, TP, SL, etc.)
|
|
8762
|
+
* @param outputDir - Output directory path (default: "./dump/strategy")
|
|
8763
|
+
* @returns Promise that resolves when all files are written
|
|
8764
|
+
*
|
|
8765
|
+
* @example
|
|
8766
|
+
* ```typescript
|
|
8767
|
+
* await outlineService.dumpSignal(
|
|
8768
|
+
* "strategy-1",
|
|
8769
|
+
* conversationHistory,
|
|
8770
|
+
* { position: "long", priceTakeProfit: 51000, priceStopLoss: 49000, minuteEstimatedTime: 60 }
|
|
8771
|
+
* );
|
|
8772
|
+
* // Creates: ./dump/strategy/strategy-1/00_system_prompt.md
|
|
8773
|
+
* // ./dump/strategy/strategy-1/01_user_message.md
|
|
8774
|
+
* // ./dump/strategy/strategy-1/02_llm_output.md
|
|
8775
|
+
* ```
|
|
8776
|
+
*/
|
|
8777
|
+
dumpSignal: (signalId: ResultId, history: MessageModel[], signal: ISignalDto, outputDir?: string) => Promise<void>;
|
|
8778
|
+
}
|
|
8779
|
+
|
|
8648
8780
|
declare const backtest: {
|
|
8649
8781
|
optimizerTemplateService: OptimizerTemplateService;
|
|
8650
8782
|
exchangeValidationService: ExchangeValidationService;
|
|
@@ -8661,6 +8793,7 @@ declare const backtest: {
|
|
|
8661
8793
|
walkerMarkdownService: WalkerMarkdownService;
|
|
8662
8794
|
heatMarkdownService: HeatMarkdownService;
|
|
8663
8795
|
partialMarkdownService: PartialMarkdownService;
|
|
8796
|
+
outlineMarkdownService: OutlineMarkdownService;
|
|
8664
8797
|
backtestLogicPublicService: BacktestLogicPublicService;
|
|
8665
8798
|
liveLogicPublicService: LiveLogicPublicService;
|
|
8666
8799
|
walkerLogicPublicService: WalkerLogicPublicService;
|
|
@@ -8700,4 +8833,4 @@ declare const backtest: {
|
|
|
8700
8833
|
loggerService: LoggerService;
|
|
8701
8834
|
};
|
|
8702
8835
|
|
|
8703
|
-
export { Backtest, type BacktestStatistics, type CandleInterval, Constant, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, type GlobalConfig, Heat, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IHeatmapStatistics, type IOptimizerCallbacks, type IOptimizerData, type IOptimizerFetchArgs, type IOptimizerFilterArgs, type IOptimizerRange, type IOptimizerSchema, type IOptimizerSource, type IOptimizerStrategy, type IOptimizerTemplate, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type IScheduledSignalRow, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultCancelled, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IStrategyTickResultScheduled, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatistics, type MessageModel, type MessageRole, MethodContextService, Optimizer, Partial$1 as Partial, type PartialData, type PartialLossContract, type PartialProfitContract, type PartialStatistics, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatistics, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, type ProgressBacktestContract, type ProgressOptimizerContract, type ProgressWalkerContract, type RiskData, Schedule, type ScheduleData, type ScheduleStatistics, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, Walker, type WalkerContract, type WalkerMetric, type WalkerStatistics, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
|
|
8836
|
+
export { Backtest, type BacktestStatistics, type CandleInterval, Constant, type DoneContract, type EntityId, ExecutionContextService, type FrameInterval, type GlobalConfig, Heat, type ICandleData, type IExchangeSchema, type IFrameSchema, type IHeatmapRow, type IHeatmapStatistics, type IOptimizerCallbacks, type IOptimizerData, type IOptimizerFetchArgs, type IOptimizerFilterArgs, type IOptimizerRange, type IOptimizerSchema, type IOptimizerSource, type IOptimizerStrategy, type IOptimizerTemplate, type IPersistBase, type IPositionSizeATRParams, type IPositionSizeFixedPercentageParams, type IPositionSizeKellyParams, type IRiskActivePosition, type IRiskCheckArgs, type IRiskSchema, type IRiskValidation, type IRiskValidationFn, type IRiskValidationPayload, type IScheduledSignalRow, type ISignalDto, type ISignalRow, type ISizingCalculateParams, type ISizingCalculateParamsATR, type ISizingCalculateParamsFixedPercentage, type ISizingCalculateParamsKelly, type ISizingSchema, type ISizingSchemaATR, type ISizingSchemaFixedPercentage, type ISizingSchemaKelly, type IStrategyPnL, type IStrategySchema, type IStrategyTickResult, type IStrategyTickResultActive, type IStrategyTickResultCancelled, type IStrategyTickResultClosed, type IStrategyTickResultIdle, type IStrategyTickResultOpened, type IStrategyTickResultScheduled, type IWalkerResults, type IWalkerSchema, type IWalkerStrategyResult, Live, type LiveStatistics, type MessageModel, type MessageRole, MethodContextService, Optimizer, Partial$1 as Partial, type PartialData, type PartialLossContract, type PartialProfitContract, type PartialStatistics, Performance, type PerformanceContract, type PerformanceMetricType, type PerformanceStatistics, PersistBase, PersistPartialAdapter, PersistRiskAdapter, PersistScheduleAdapter, PersistSignalAdapter, PositionSize, type ProgressBacktestContract, type ProgressOptimizerContract, type ProgressWalkerContract, type RiskData, Schedule, type ScheduleData, type ScheduleStatistics, type SignalData, type SignalInterval, type TPersistBase, type TPersistBaseCtor, Walker, type WalkerContract, type WalkerMetric, type WalkerStatistics, addExchange, addFrame, addOptimizer, addRisk, addSizing, addStrategy, addWalker, dumpSignal, emitters, formatPrice, formatQuantity, getAveragePrice, getCandles, getDate, getMode, backtest as lib, listExchanges, listFrames, listOptimizers, listRisks, listSizings, listStrategies, listWalkers, listenBacktestProgress, listenDoneBacktest, listenDoneBacktestOnce, listenDoneLive, listenDoneLiveOnce, listenDoneWalker, listenDoneWalkerOnce, listenError, listenExit, listenOptimizerProgress, listenPartialLoss, listenPartialLossOnce, listenPartialProfit, listenPartialProfitOnce, listenPerformance, listenSignal, listenSignalBacktest, listenSignalBacktestOnce, listenSignalLive, listenSignalLiveOnce, listenSignalOnce, listenValidation, listenWalker, listenWalkerComplete, listenWalkerOnce, listenWalkerProgress, setConfig, setLogger };
|