Spaces:
Running
Running
| <html class="default" lang="en" data-base=".."><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>cli/readme | backtest-kit</title><meta name="description" content="Documentation for backtest-kit"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script><script async src="../assets/hierarchy.js" id="tsd-hierarchy-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><div class="table-cell" id="tsd-search"><div class="field"><label for="tsd-search-field" class="tsd-widget tsd-toolbar-icon search no-caption"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></label><input type="text" id="tsd-search-field" aria-label="Search"/></div><div class="field"><div id="tsd-toolbar-links"></div></div><ul class="results"><li class="state loading">Preparing search index...</li><li class="state failure">The search index is not available</li></ul><a href="../index.html" class="title">backtest-kit</a></div><div class="table-cell" id="tsd-widgets"><a href="#" class="tsd-widget tsd-toolbar-icon menu no-caption" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb"><li><a href="../modules.html">backtest-kit</a></li><li><a href="cli_readme.html">cli/readme</a></li></ul></div><div class="tsd-panel tsd-typography"><img src="https://github.com/tripolskypetr/backtest-kit/raw/refs/heads/master/assets/square_compasses.svg" height="45px" align="right"> | |
| <a id="π-backtest-kitcli" class="tsd-anchor"></a><h1 class="tsd-anchor-link">π @backtest-kit/cli<a href="#π-backtest-kitcli" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h1><blockquote> | |
| <p>Zero-boilerplate CLI for launching backtests, paper trading, and live trading. Run any backtest-kit strategy from the command line β no setup code required.</p> | |
| </blockquote> | |
| <p><img src="https://raw.githubusercontent.com/tripolskypetr/backtest-kit/HEAD/assets/screenshots/screenshot16.png" alt="screenshot"></p> | |
| <p><a href="https://deepwiki.com/tripolskypetr/backtest-kit"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a> | |
| <a href="https://npmjs.org/package/@backtest-kit/cli"><img src="https://img.shields.io/npm/v/@backtest-kit/cli.svg?style=flat-square" alt="npm"></a> | |
| <a href=""><img src="https://img.shields.io/badge/TypeScript-5.0+-blue" alt="TypeScript"></a></p> | |
| <p>Point the CLI at your strategy file, choose a mode, and it handles exchange connectivity, candle caching, UI dashboard, and Telegram notifications for you.</p> | |
| <p>π <strong><a href="https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html">Backtest Kit Docs</a></strong> | π <strong><a href="https://github.com/tripolskypetr/backtest-kit">GitHub</a></strong></p> | |
| <blockquote> | |
| <p><strong>New to backtest-kit?</strong> The fastest way to get a real, production-ready setup is to clone the <a href="https://github.com/tripolskypetr/backtest-kit/tree/master/example">reference implementation</a> β a fully working news-sentiment AI trading system with LLM forecasting, multi-timeframe data, and a documented February 2026 backtest. Start there instead of from scratch.</p> | |
| </blockquote> | |
| <a id="β¨-features" class="tsd-anchor"></a><h2 class="tsd-anchor-link">β¨ Features<a href="#β¨-features" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><ul> | |
| <li>π <strong>Zero Config</strong>: Run <code>npx @backtest-kit/cli --backtest ./strategy.mjs</code> β no boilerplate needed</li> | |
| <li>π <strong>Four Modes</strong>: Backtest on historical data, walker A/B comparison, paper trade on live prices, or deploy live bots</li> | |
| <li>πΎ <strong>Auto Candle Cache</strong>: Warms OHLCV cache for all required intervals before backtest starts</li> | |
| <li>π <strong>Web Dashboard</strong>: Launch <code>@backtest-kit/ui</code> with a single <code>--ui</code> flag</li> | |
| <li>π¬ <strong>Telegram Alerts</strong>: Send formatted trade notifications with charts via <code>--telegram</code></li> | |
| <li>π <strong>Default Binance</strong>: CCXT Binance exchange schema registered automatically when none is provided</li> | |
| <li>π§© <strong>Module Hooks</strong>: Drop a <code>live.module.mjs</code>, <code>paper.module.mjs</code>, or <code>backtest.module.mjs</code> to register a <code>Broker</code> adapter. No manual wiring needed.</li> | |
| <li>ποΈ <strong>Transactional Live Orders</strong>: Broker adapter intercepts every trade mutation before internal state changes β exchange rejection rolls back the operation atomically.</li> | |
| <li>π <strong>Pluggable Logger</strong>: Override the built-in logger with <code>setLogger()</code> from your strategy module</li> | |
| <li>π <strong>Graceful Shutdown</strong>: SIGINT stops the active run and cleans up all subscriptions safely</li> | |
| </ul> | |
| <a id="π-what-it-does" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π What It Does<a href="#π-what-it-does" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> wraps the <code>backtest-kit</code> engine and resolves all scaffolding automatically:</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Mode</th> | |
| <th>Command Line Args</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><strong>Backtest</strong></td> | |
| <td><code>--backtest</code></td> | |
| <td>Run strategy on historical candle data</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Walker</strong></td> | |
| <td><code>--walker</code></td> | |
| <td>A/B compare multiple strategies on the same historical data</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Paper</strong></td> | |
| <td><code>--paper</code></td> | |
| <td>Live prices, no real orders</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Live</strong></td> | |
| <td><code>--live</code></td> | |
| <td>Real trades via exchange API</td> | |
| </tr> | |
| <tr> | |
| <td><strong>UI Dashboard</strong></td> | |
| <td><code>--ui</code></td> | |
| <td>Web dashboard at <code>http://localhost:60050</code></td> | |
| </tr> | |
| <tr> | |
| <td><strong>Telegram</strong></td> | |
| <td><code>--telegram</code></td> | |
| <td>Trade notifications with price charts</td> | |
| </tr> | |
| <tr> | |
| <td><strong>PineScript</strong></td> | |
| <td><code>--pine</code></td> | |
| <td>Run a local <code>.pine</code> indicator against exchange data</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Pine Editor</strong></td> | |
| <td><code>--editor</code></td> | |
| <td>Open the visual Pine Script editor in the browser</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Candle Dump</strong></td> | |
| <td><code>--dump</code></td> | |
| <td>Fetch and save raw OHLCV candles to a file</td> | |
| </tr> | |
| <tr> | |
| <td><strong>PnL Debug</strong></td> | |
| <td><code>--pnldebug</code></td> | |
| <td>Simulate per-minute PnL for a given entry price and direction</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Flush</strong></td> | |
| <td><code>--flush</code></td> | |
| <td>Delete report/log/markdown/agent folders from strategy dump dir</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Init Project</strong></td> | |
| <td><code>--init</code></td> | |
| <td>Scaffold a new backtest-kit project</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="π-installation" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π Installation<a href="#π-installation" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Add <code>@backtest-kit/cli</code> to your project and wire it up in <code>package.json</code> scripts:</p> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">install</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest ./src/index.mjs"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"paper"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --paper ./src/index.mjs"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"start"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --live ./src/index.mjs"</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-16">"dependencies"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"@backtest-kit/cli"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest-kit"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"ccxt"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Or run once without installing:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--backtest</span><span class="hl-1"> </span><span class="hl-2">./src/index.mjs</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π-quick-start" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π Quick Start<a href="#π-quick-start" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Create your strategy entry point (<code>src/index.mjs</code>). The file registers schemas via <code>backtest-kit</code> β <code>@backtest-kit/cli</code> is only the runner:</p> | |
| <pre><code class="javascript"><span class="hl-6">// src/index.mjs</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">addStrategySchema</span><span class="hl-1">, </span><span class="hl-5">addExchangeSchema</span><span class="hl-1">, </span><span class="hl-5">addFrameSchema</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'backtest-kit'</span><span class="hl-1">;</span><br/><span class="hl-4">import</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1"> </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'ccxt'</span><span class="hl-1">;</span><br/><br/><span class="hl-6">// Register exchange</span><br/><span class="hl-0">addExchangeSchema</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">exchangeName:</span><span class="hl-1"> </span><span class="hl-2">'binance'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">getCandles</span><span class="hl-5">:</span><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">, </span><span class="hl-5">limit</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">exchange</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1">.</span><span class="hl-0">binance</span><span class="hl-1">();</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">ohlcv</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">exchange</span><span class="hl-1">.</span><span class="hl-0">fetchOHLCV</span><span class="hl-1">(</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">.</span><span class="hl-0">getTime</span><span class="hl-1">(), </span><span class="hl-5">limit</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-5">ohlcv</span><span class="hl-1">.</span><span class="hl-0">map</span><span class="hl-1">(([</span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">]) </span><span class="hl-3">=></span><span class="hl-1"> ({</span><br/><span class="hl-1"> </span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">,</span><br/><span class="hl-1"> }));</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-0">formatPrice</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">price</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">price</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">2</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-0">formatQuantity</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">quantity</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">quantity</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">8</span><span class="hl-1">),</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-6">// Register frame (backtest only)</span><br/><span class="hl-0">addFrameSchema</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">frameName:</span><span class="hl-1"> </span><span class="hl-2">'feb-2024'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">interval:</span><span class="hl-1"> </span><span class="hl-2">'1m'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">startDate:</span><span class="hl-1"> </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-0">Date</span><span class="hl-1">(</span><span class="hl-2">'2024-02-01'</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-5">endDate:</span><span class="hl-1"> </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-0">Date</span><span class="hl-1">(</span><span class="hl-2">'2024-02-29'</span><span class="hl-1">),</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-6">// Register strategy</span><br/><span class="hl-0">addStrategySchema</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">strategyName:</span><span class="hl-1"> </span><span class="hl-2">'my-strategy'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">interval:</span><span class="hl-1"> </span><span class="hl-2">'15m'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">getSignal</span><span class="hl-5">:</span><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">// return signal or null</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-3">null</span><span class="hl-1">;</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Run a backtest:</p> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">backtest</span><span class="hl-1"> </span><span class="hl-3">--</span><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Run with UI dashboard and Telegram:</p> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">backtest</span><span class="hl-1"> </span><span class="hl-3">--</span><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-3">--ui</span><span class="hl-1"> </span><span class="hl-3">--telegram</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Run live trading:</p> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">start</span><span class="hl-1"> </span><span class="hl-3">--</span><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-3">--ui</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="ποΈ-cli-flags" class="tsd-anchor"></a><h2 class="tsd-anchor-link">ποΈ CLI Flags<a href="#ποΈ-cli-flags" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><table> | |
| <thead> | |
| <tr> | |
| <th>Command Line Args</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>--backtest</code></td> | |
| <td>boolean</td> | |
| <td>Run historical backtest (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--walker</code></td> | |
| <td>boolean</td> | |
| <td>Run Walker A/B strategy comparison (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--paper</code></td> | |
| <td>boolean</td> | |
| <td>Paper trading (live prices, no orders) (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--live</code></td> | |
| <td>boolean</td> | |
| <td>Run live trading (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--ui</code></td> | |
| <td>boolean</td> | |
| <td>Start web UI dashboard (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--telegram</code></td> | |
| <td>boolean</td> | |
| <td>Enable Telegram notifications (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--verbose</code></td> | |
| <td>boolean</td> | |
| <td>Log each candle fetch (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--noCache</code></td> | |
| <td>boolean</td> | |
| <td>Skip candle cache warming before backtest (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--noFlush</code></td> | |
| <td>boolean</td> | |
| <td>Skip removing report/log/markdown/agent folders before backtest run (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--symbol</code></td> | |
| <td>string</td> | |
| <td>Trading pair (default: <code>"BTCUSDT"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--strategy</code></td> | |
| <td>string</td> | |
| <td>Strategy name (default: first registered)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--exchange</code></td> | |
| <td>string</td> | |
| <td>Exchange name (default: first registered)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--frame</code></td> | |
| <td>string</td> | |
| <td>Backtest frame name (default: first registered)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--cacheInterval</code></td> | |
| <td>string</td> | |
| <td>Intervals to pre-cache before backtest (default: <code>"1m, 15m, 30m, 4h"</code>)</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p><strong>Positional argument (required):</strong> path to your strategy entry point file (set once in <code>package.json</code> scripts).</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest ./src/index.mjs"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π-execution-modes" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π Execution Modes<a href="#π-execution-modes" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><a id="backtest" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Backtest<a href="#backtest" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Runs the strategy against historical candle data using a registered <code>FrameSchema</code>.</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest --symbol ETHUSDT --strategy my-strategy --exchange binance --frame feb-2024 --cacheInterval </span><span class="hl-13">\"</span><span class="hl-2">1m, 15m, 1h, 4h</span><span class="hl-13">\"</span><span class="hl-2"> ./src/index.mjs"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">backtest</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Before running, the CLI removes the <code>report</code>, <code>log</code>, <code>markdown</code>, and <code>agent</code> folders from the strategy's <code>dump/</code> directory, then warms the candle cache for every interval in <code>--cacheInterval</code>. On the next run, cached data is used directly β no API calls needed. Pass <code>--noCache</code> to skip cache warming, <code>--noFlush</code> to keep existing output folders.</p> | |
| <a id="paper-trading" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Paper Trading<a href="#paper-trading" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Connects to the live exchange but does not place real orders. Identical code path to live β safe for strategy validation.</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"paper"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --paper --symbol BTCUSDT ./src/index.mjs"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">paper</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="live-trading" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Live Trading<a href="#live-trading" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Deploys a real trading bot. Requires exchange API keys configured in your <code>.env</code> or environment.</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"start"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --live --ui --telegram --symbol BTCUSDT ./src/index.mjs"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">start</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="walker--ab-strategy-comparison" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Walker β A/B Strategy Comparison<a href="#walker--ab-strategy-comparison" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Runs the same historical period against multiple strategy files and prints a ranked comparison report. Use it to pick the best variant before deploying to backtest or live.</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"walker"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --walker --symbol BTCUSDT --noCache ./content/feb_2026_v1.strategy.ts ./content/feb_2026_v2.strategy.ts ./content/feb_2026_v3.strategy.ts"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">walker</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Each positional argument is a separate strategy entry point. Before loading them, the CLI removes the <code>report</code>, <code>log</code>, <code>markdown</code>, and <code>agent</code> folders from each entry point's <code>dump/</code> directory. Pass <code>--noFlush</code> to keep existing output. All files are loaded without changing <code>process.cwd()</code> β <code>.env</code> is read from the working directory only. After loading, <code>addWalkerSchema</code> is called automatically using the exchange and frame registered by the strategy files.</p> | |
| <p>If no frame is registered, the CLI falls back to the last 31 days from <code>Date.now()</code> with a console warning.</p> | |
| <p><strong>Walker-specific flags:</strong></p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Flag</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>--walker</code></td> | |
| <td>boolean</td> | |
| <td>Enable Walker comparison mode</td> | |
| </tr> | |
| <tr> | |
| <td><code>--symbol</code></td> | |
| <td>string</td> | |
| <td>Trading pair (default: <code>"BTCUSDT"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--cacheInterval</code></td> | |
| <td>string</td> | |
| <td>Intervals to pre-cache (default: <code>"1m, 15m, 30m, 4h"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--noCache</code></td> | |
| <td>boolean</td> | |
| <td>Skip candle cache warming (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--noFlush</code></td> | |
| <td>boolean</td> | |
| <td>Skip removing report/log/markdown/agent folders before walker run (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--verbose</code></td> | |
| <td>boolean</td> | |
| <td>Log each candle fetch and strategy progress (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--output</code></td> | |
| <td>string</td> | |
| <td>Output file base name (default: <code>walker_{SYMBOL}_{TIMESTAMP}</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--json</code></td> | |
| <td>boolean</td> | |
| <td>Save results as JSON to <code>./dump/<output>.json</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>--markdown</code></td> | |
| <td>boolean</td> | |
| <td>Save report as Markdown to <code>./dump/<output>.md</code></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p><strong>Output modes:</strong></p> | |
| <ul> | |
| <li>No flag β print Markdown report to stdout</li> | |
| <li><code>--json</code> β save <code>Walker.getData()</code> result as JSON and exit</li> | |
| <li><code>--markdown</code> β save <code>Walker.getReport()</code> as <code>.md</code> file and exit</li> | |
| </ul> | |
| <p><strong>Module hook:</strong> <code>./modules/walker.module</code> is loaded automatically before the comparison starts (same rules as other modes β <code>.ts</code>, <code>.mjs</code>, <code>.cjs</code> tried in order).</p> | |
| <p><strong>Example β compare three variants and save the report:</strong></p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--walker</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--noCache</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--markdown</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--output</span><span class="hl-1"> </span><span class="hl-2">feb_2026_comparison</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-2">./content/feb_2026_v1.strategy.ts</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-2">./content/feb_2026_v2.strategy.ts</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-2">./content/feb_2026_v3.strategy.ts</span><br/><span class="hl-6"># β ./dump/feb_2026_comparison.md</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="ποΈ-monorepo-usage" class="tsd-anchor"></a><h2 class="tsd-anchor-link">ποΈ Monorepo Usage<a href="#ποΈ-monorepo-usage" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> works out of the box in a monorepo where each strategy lives in its own subdirectory. When the CLI loads your entry point file, it automatically changes the working directory to the file's location β so all relative paths (<code>dump/</code>, <code>modules/</code>, <code>template/</code>) resolve inside that strategy's folder, not the project root.</p> | |
| <a id="how-it-works" class="tsd-anchor"></a><h3 class="tsd-anchor-link">How It Works<a href="#how-it-works" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Internally, <code>ResolveService</code> does the following before executing your entry point:</p> | |
| <pre><code><span class="hl-5">process</span><span class="hl-1">.</span><span class="hl-0">chdir</span><span class="hl-1">(</span><span class="hl-5">path</span><span class="hl-1">.</span><span class="hl-0">dirname</span><span class="hl-1">(</span><span class="hl-5">entryPoint</span><span class="hl-1">)) </span><span class="hl-6">// cwd β strategy directory</span><br/><span class="hl-5">dotenv</span><span class="hl-1">.</span><span class="hl-0">config</span><span class="hl-1">({ </span><span class="hl-5">path:</span><span class="hl-1"> </span><span class="hl-5">rootDir</span><span class="hl-1"> + </span><span class="hl-2">'/.env'</span><span class="hl-1"> }) </span><span class="hl-6">// load root .env first</span><br/><span class="hl-5">dotenv</span><span class="hl-1">.</span><span class="hl-0">config</span><span class="hl-1">({ </span><span class="hl-5">path:</span><span class="hl-1"> </span><span class="hl-5">strategyDir</span><span class="hl-1"> + </span><span class="hl-2">'/.env'</span><span class="hl-1">, </span><span class="hl-5">override:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1"> }) </span><span class="hl-6">// strategy .env overrides</span> | |
| </code><button>Copy</button></pre> | |
| <p>Everything that follows β candle cache warming, report generation, module loading, template resolution β uses the new cwd automatically.</p> | |
| <a id="project-structure" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Project Structure<a href="#project-structure" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code><span class="hl-5">monorepo</span><span class="hl-1">/</span><br/><span class="hl-1">βββ </span><span class="hl-5">package</span><span class="hl-1">.</span><span class="hl-5">json</span><span class="hl-1"> # </span><span class="hl-5">root</span><span class="hl-1"> </span><span class="hl-0">scripts</span><span class="hl-1"> (</span><span class="hl-5">one</span><span class="hl-1"> </span><span class="hl-5">per</span><span class="hl-1"> </span><span class="hl-5">strategy</span><span class="hl-1">)</span><br/><span class="hl-1">βββ .</span><span class="hl-5">env</span><span class="hl-1"> # </span><span class="hl-5">shared</span><span class="hl-1"> </span><span class="hl-8">API</span><span class="hl-1"> </span><span class="hl-0">keys</span><span class="hl-1"> (</span><span class="hl-5">exchange</span><span class="hl-1">, </span><span class="hl-5">Telegram</span><span class="hl-1">, </span><span class="hl-5">etc</span><span class="hl-1">.)</span><br/><span class="hl-1">βββ </span><span class="hl-5">strategies</span><span class="hl-1">/</span><br/><span class="hl-1"> βββ </span><span class="hl-5">oct_2025</span><span class="hl-1">/</span><br/><span class="hl-1"> β βββ </span><span class="hl-5">index</span><span class="hl-1">.</span><span class="hl-5">mjs</span><span class="hl-1"> # </span><span class="hl-5">entry</span><span class="hl-1"> </span><span class="hl-5">point</span><span class="hl-1"> β </span><span class="hl-5">registers</span><span class="hl-1"> </span><span class="hl-5">exchange</span><span class="hl-1">/</span><span class="hl-5">frame</span><span class="hl-1">/</span><span class="hl-5">strategy</span><span class="hl-1"> </span><span class="hl-5">schemas</span><br/><span class="hl-1"> β βββ .</span><span class="hl-5">env</span><span class="hl-1"> # </span><span class="hl-5">overrides</span><span class="hl-1"> </span><span class="hl-5">root</span><span class="hl-1"> .</span><span class="hl-5">env</span><span class="hl-1"> </span><span class="hl-5">for</span><span class="hl-1"> </span><span class="hl-3">this</span><span class="hl-1"> </span><span class="hl-5">strategy</span><span class="hl-1"> </span><br/><span class="hl-1"> β βββ </span><span class="hl-0">modules</span><span class="hl-1"> (</span><span class="hl-5">optional</span><span class="hl-1">)</span><br/><span class="hl-1"> β | βββ </span><span class="hl-5">live</span><span class="hl-1">.</span><span class="hl-5">module</span><span class="hl-1">.</span><span class="hl-5">mjs</span><span class="hl-1"> # </span><span class="hl-5">broker</span><span class="hl-1"> </span><span class="hl-5">adapter</span><span class="hl-1"> </span><span class="hl-5">for</span><span class="hl-1"> --</span><span class="hl-5">live</span><span class="hl-1"> </span><span class="hl-0">mode</span><span class="hl-1"> (</span><span class="hl-5">optional</span><span class="hl-1">)</span><br/><span class="hl-1"> β | βββ </span><span class="hl-5">paper</span><span class="hl-1">.</span><span class="hl-5">module</span><span class="hl-1">.</span><span class="hl-5">mjs</span><span class="hl-1"> # </span><span class="hl-5">broker</span><span class="hl-1"> </span><span class="hl-5">adapter</span><span class="hl-1"> </span><span class="hl-5">for</span><span class="hl-1"> --</span><span class="hl-5">paper</span><span class="hl-1"> </span><span class="hl-0">mode</span><span class="hl-1"> (</span><span class="hl-5">optional</span><span class="hl-1">)</span><br/><span class="hl-1"> β | βββ </span><span class="hl-5">backtest</span><span class="hl-1">.</span><span class="hl-5">module</span><span class="hl-1">.</span><span class="hl-5">mjs</span><span class="hl-1"> # </span><span class="hl-5">broker</span><span class="hl-1"> </span><span class="hl-5">adapter</span><span class="hl-1"> </span><span class="hl-5">for</span><span class="hl-1"> --</span><span class="hl-5">backtest</span><span class="hl-1"> </span><span class="hl-0">mode</span><span class="hl-1"> (</span><span class="hl-5">optional</span><span class="hl-1">)</span><br/><span class="hl-1"> β βββ </span><span class="hl-5">template</span><span class="hl-1">/ # </span><span class="hl-5">custom</span><span class="hl-1"> </span><span class="hl-5">Mustache</span><span class="hl-1"> </span><span class="hl-0">templates</span><span class="hl-1"> (</span><span class="hl-5">optional</span><span class="hl-1">)</span><br/><span class="hl-1"> β βββ </span><span class="hl-5">dump</span><span class="hl-1">/ # </span><span class="hl-5">auto</span><span class="hl-1">-</span><span class="hl-10">created</span><span class="hl-1">: </span><span class="hl-5">candle</span><span class="hl-1"> </span><span class="hl-5">cache</span><span class="hl-1"> + </span><span class="hl-5">backtest</span><span class="hl-1"> </span><span class="hl-5">reports</span><br/><span class="hl-1"> βββ </span><span class="hl-5">dec_2025</span><span class="hl-1">/</span><br/><span class="hl-1"> βββ </span><span class="hl-5">index</span><span class="hl-1">.</span><span class="hl-5">mjs</span><br/><span class="hl-1"> βββ .</span><span class="hl-5">env</span><br/><span class="hl-1"> βββ </span><span class="hl-5">dump</span><span class="hl-1">/</span> | |
| </code><button>Copy</button></pre> | |
| <a id="root-packagejson" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Root <code>package.json</code><a href="#root-packagejson" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest:oct"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest ./strategies/oct_2025/index.mjs"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest:dec"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest ./strategies/dec_2025/index.mjs"</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-16">"dependencies"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"@backtest-kit/cli"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest-kit"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"ccxt"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">backtest:oct</span><br/><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">backtest:dec</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="isolated-resources-per-strategy" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Isolated Resources Per Strategy<a href="#isolated-resources-per-strategy" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Resource</th> | |
| <th>Path (relative to strategy dir)</th> | |
| <th>Isolated</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>Candle cache</td> | |
| <td><code>./dump/data/candle/</code></td> | |
| <td>β per-strategy</td> | |
| </tr> | |
| <tr> | |
| <td>Backtest reports</td> | |
| <td><code>./dump/</code></td> | |
| <td>β per-strategy</td> | |
| </tr> | |
| <tr> | |
| <td>Broker module (live)</td> | |
| <td><code>./modules/live.module.mjs</code></td> | |
| <td>β per-strategy</td> | |
| </tr> | |
| <tr> | |
| <td>Broker module (paper)</td> | |
| <td><code>./modules/paper.module.mjs</code></td> | |
| <td>β per-strategy</td> | |
| </tr> | |
| <tr> | |
| <td>Broker module (backtest)</td> | |
| <td><code>./modules/backtest.module.mjs</code></td> | |
| <td>β per-strategy</td> | |
| </tr> | |
| <tr> | |
| <td>Config module (walker)</td> | |
| <td><code>./modules/walker.module.mjs</code></td> | |
| <td>β loaded once</td> | |
| </tr> | |
| <tr> | |
| <td>Telegram templates</td> | |
| <td><code>./template/*.mustache</code></td> | |
| <td>β per-strategy</td> | |
| </tr> | |
| <tr> | |
| <td>Environment variables</td> | |
| <td><code>./.env</code> (overrides root)</td> | |
| <td>β per-strategy</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p>Each strategy run produces its own <code>dump/</code> directory, making it straightforward to compare results across time periods β both by inspection and by pointing an AI agent at a specific strategy folder.</p> | |
| <a id="π-shared-import-aliases" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π Shared Import Aliases<a href="#π-shared-import-aliases" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> automatically turns every <strong>top-level folder</strong> in <code>process.cwd()</code> into a bare import alias available inside any strategy file. No configuration needed β just create the folder.</p> | |
| <a id="how-it-works-1" class="tsd-anchor"></a><h3 class="tsd-anchor-link">How It Works<a href="#how-it-works-1" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>When the CLI loads a strategy file, it scans the current working directory for subdirectories and registers each one as an import alias. The alias name is the folder name. Both barrel imports and deep subpath imports are supported:</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Import</th> | |
| <th>Resolves to</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>import { fn } from "utils"</code></td> | |
| <td><code><cwd>/utils/index.ts</code> (or <code>.js</code>, <code>.mjs</code>, <code>.cjs</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>import { calcRSI } from "math/rsi"</code></td> | |
| <td><code><cwd>/math/rsi.ts</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>import { research } from "logic"</code></td> | |
| <td><code><cwd>/logic/index.ts</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>import { ResearchResponseContract } from "logic/contract/ResearchResponse.contract"</code></td> | |
| <td><code><cwd>/logic/contract/ResearchResponse.contract.ts</code></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="project-structure-1" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Project Structure<a href="#project-structure-1" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code><span class="hl-5">my</span><span class="hl-1">-</span><span class="hl-5">project</span><span class="hl-1">/</span><br/><span class="hl-1">βββ </span><span class="hl-5">utils</span><span class="hl-1">/ β </span><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">formatDate</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"utils"</span><br/><span class="hl-1">β βββ </span><span class="hl-5">index</span><span class="hl-1">.</span><span class="hl-5">ts</span><br/><span class="hl-1">βββ </span><span class="hl-5">math</span><span class="hl-1">/ β </span><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">calcRSI</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"math/rsi"</span><br/><span class="hl-1">β βββ </span><span class="hl-5">rsi</span><span class="hl-1">.</span><span class="hl-5">ts</span><br/><span class="hl-1">βββ </span><span class="hl-5">logic</span><span class="hl-1">/ β </span><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">research</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"logic"</span><br/><span class="hl-1">β βββ </span><span class="hl-5">index</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> β </span><span class="hl-5">barrel</span><br/><span class="hl-1">β βββ </span><span class="hl-5">contract</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">ResearchResponse</span><span class="hl-1">.</span><span class="hl-5">contract</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> β </span><span class="hl-4">import</span><span class="hl-1"> { ... } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"logic/contract/ResearchResponse.contract"</span><br/><span class="hl-1">βββ </span><span class="hl-5">content</span><span class="hl-1">/</span><br/><span class="hl-1"> βββ </span><span class="hl-5">feb_2026</span><span class="hl-1">.</span><span class="hl-5">strategy</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> β </span><span class="hl-5">uses</span><span class="hl-1"> </span><span class="hl-5">all</span><span class="hl-1"> </span><span class="hl-5">three</span><span class="hl-1"> </span><span class="hl-5">aliases</span><span class="hl-1"> </span><span class="hl-5">freely</span><br/><span class="hl-1"> βββ </span><span class="hl-5">mar_2026</span><span class="hl-1">.</span><span class="hl-5">strategy</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> β </span><span class="hl-5">same</span><span class="hl-1"> </span><span class="hl-5">aliases</span><span class="hl-1">, </span><span class="hl-5">no</span><span class="hl-1"> </span><span class="hl-5">duplication</span> | |
| </code><button>Copy</button></pre> | |
| <p>This lets you extract shared utilities, math helpers, or AI agent logic (e.g. <code>agent-swarm-kit</code> workflows) into named folders and reuse them across every strategy in the project without relative path hell.</p> | |
| <a id="typescript-support" class="tsd-anchor"></a><h3 class="tsd-anchor-link">TypeScript Support<a href="#typescript-support" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Add a matching <code>paths</code> entry to your <code>tsconfig.json</code> so the editor resolves the aliases:</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"compilerOptions"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"moduleResolution"</span><span class="hl-1">: </span><span class="hl-2">"bundler"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"paths"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"logic"</span><span class="hl-1">: [</span><span class="hl-2">"./logic/index.ts"</span><span class="hl-1">],</span><br/><span class="hl-1"> </span><span class="hl-16">"logic/*"</span><span class="hl-1">: [</span><span class="hl-2">"./logic/*"</span><span class="hl-1">],</span><br/><span class="hl-1"> </span><span class="hl-16">"math"</span><span class="hl-1">: [</span><span class="hl-2">"./math/index.ts"</span><span class="hl-1">],</span><br/><span class="hl-1"> </span><span class="hl-16">"math/*"</span><span class="hl-1">: [</span><span class="hl-2">"./math/*"</span><span class="hl-1">],</span><br/><span class="hl-1"> </span><span class="hl-16">"utils"</span><span class="hl-1">: [</span><span class="hl-2">"./utils/index.ts"</span><span class="hl-1">],</span><br/><span class="hl-1"> </span><span class="hl-16">"utils/*"</span><span class="hl-1">: [</span><span class="hl-2">"./utils/*"</span><span class="hl-1">]</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-16">"include"</span><span class="hl-1">: [</span><br/><span class="hl-1"> </span><span class="hl-2">"./logic"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">"./math"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">"./utils"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">"./content"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">"./modules"</span><span class="hl-1">,</span><br/><span class="hl-1"> ],</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π-integrations" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π Integrations<a href="#π-integrations" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><a id="web-dashboard---ui" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Web Dashboard (<code>--ui</code>)<a href="#web-dashboard---ui" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Starts <code>@backtest-kit/ui</code> server. Access the interactive dashboard at:</p> | |
| <pre><code><span class="hl-10">http</span><span class="hl-1">:</span><span class="hl-6">//localhost:60050</span> | |
| </code><button>Copy</button></pre> | |
| <p>Customize host/port via environment variables <code>CC_WWWROOT_HOST</code> and <code>CC_WWWROOT_PORT</code>.</p> | |
| <a id="symbol-list-symbolconfig" class="tsd-anchor"></a><h4 class="tsd-anchor-link">Symbol List (<code>symbol.config</code>)<a href="#symbol-list-symbolconfig" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p>By default the UI shows all symbols from the exchange. To restrict or reorder the list, create a <code>config/symbol.config</code> file in your strategy directory (next to the entry point).</p> | |
| <p><strong>Resolution order β first match wins:</strong></p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Priority</th> | |
| <th>Path</th> | |
| <th>Notes</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>1</td> | |
| <td><code>{strategyDir}/config/symbol.config</code></td> | |
| <td>per-strategy override (cwd after <code>chdir</code>)</td> | |
| </tr> | |
| <tr> | |
| <td>2</td> | |
| <td><code>{projectRoot}/config/symbol.config</code></td> | |
| <td>project-root override (cwd where <code>npx</code> was invoked)</td> | |
| </tr> | |
| <tr> | |
| <td>3</td> | |
| <td><code>@backtest-kit/cli/config/symbol.config</code></td> | |
| <td>built-in default shipped with the package</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p>Supported file formats (<code>.ts</code>, <code>.cjs</code>, <code>.mjs</code>, <code>.js</code> tried automatically):</p> | |
| <pre><code class="ts"><span class="hl-6">// config/symbol.config.ts</span><br/><span class="hl-4">export</span><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">symbol_list</span><span class="hl-1"> = [</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">icon:</span><span class="hl-1"> </span><span class="hl-2">"/icon/btc.png"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">logo:</span><span class="hl-1"> </span><span class="hl-2">"/icon/128/btc.png"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">symbol:</span><span class="hl-1"> </span><span class="hl-2">"BTCUSDT"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">displayName:</span><span class="hl-1"> </span><span class="hl-2">"Bitcoin"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">color:</span><span class="hl-1"> </span><span class="hl-2">"#F7931A"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">priority:</span><span class="hl-1"> </span><span class="hl-7">50</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">description:</span><span class="hl-1"> </span><span class="hl-2">"Bitcoin - the first and most popular cryptocurrency"</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">icon:</span><span class="hl-1"> </span><span class="hl-2">"/icon/eth.png"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">logo:</span><span class="hl-1"> </span><span class="hl-2">"/icon/128/eth.png"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">symbol:</span><span class="hl-1"> </span><span class="hl-2">"ETHUSDT"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">displayName:</span><span class="hl-1"> </span><span class="hl-2">"Ethereum"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">color:</span><span class="hl-1"> </span><span class="hl-2">"#6F42C1"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">priority:</span><span class="hl-1"> </span><span class="hl-7">50</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">description:</span><span class="hl-1"> </span><span class="hl-2">"Ethereum - a blockchain platform for smart contracts"</span><span class="hl-1">,</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">];</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="notification-filter-notificationconfig" class="tsd-anchor"></a><h4 class="tsd-anchor-link">Notification Filter (<code>notification.config</code>)<a href="#notification-filter-notificationconfig" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p>Controls which notification categories are shown in the UI dashboard. Create a <code>config/notification.config</code> file in your strategy directory to override the defaults.</p> | |
| <p><strong>Resolution order β first match wins:</strong></p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Priority</th> | |
| <th>Path</th> | |
| <th>Notes</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>1</td> | |
| <td><code>{strategyDir}/config/notification.config</code></td> | |
| <td>per-strategy override (cwd after <code>chdir</code>)</td> | |
| </tr> | |
| <tr> | |
| <td>2</td> | |
| <td><code>{projectRoot}/config/notification.config</code></td> | |
| <td>project-root override (cwd where <code>npx</code> was invoked)</td> | |
| </tr> | |
| <tr> | |
| <td>3</td> | |
| <td><code>@backtest-kit/cli/config/notification.config</code></td> | |
| <td>built-in default shipped with the package</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p><strong>Default values (built-in):</strong></p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Key</th> | |
| <th>Default</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>signal</code></td> | |
| <td><code>true</code></td> | |
| <td>Signal lifecycle: opened, scheduled, closed, cancelled</td> | |
| </tr> | |
| <tr> | |
| <td><code>risk</code></td> | |
| <td><code>true</code></td> | |
| <td>Risk manager rejection notifications</td> | |
| </tr> | |
| <tr> | |
| <td><code>info</code></td> | |
| <td><code>true</code></td> | |
| <td>Informational messages attached to an active signal</td> | |
| </tr> | |
| <tr> | |
| <td><code>breakeven</code></td> | |
| <td><code>true</code></td> | |
| <td>Breakeven level reached</td> | |
| </tr> | |
| <tr> | |
| <td><code>common_error</code></td> | |
| <td><code>true</code></td> | |
| <td>Non-fatal runtime errors</td> | |
| </tr> | |
| <tr> | |
| <td><code>critical_error</code></td> | |
| <td><code>true</code></td> | |
| <td>Fatal errors that terminate the session</td> | |
| </tr> | |
| <tr> | |
| <td><code>validation_error</code></td> | |
| <td><code>true</code></td> | |
| <td>Strategy config / input validation errors</td> | |
| </tr> | |
| <tr> | |
| <td><code>strategy_commit</code></td> | |
| <td><code>true</code></td> | |
| <td>All committed actions (partial close, DCA, trailing, etc.)</td> | |
| </tr> | |
| <tr> | |
| <td><code>partial_loss</code></td> | |
| <td><code>false</code></td> | |
| <td>Partial loss level reached (before commit)</td> | |
| </tr> | |
| <tr> | |
| <td><code>partial_profit</code></td> | |
| <td><code>false</code></td> | |
| <td>Partial profit level reached (before commit)</td> | |
| </tr> | |
| <tr> | |
| <td><code>signal_sync</code></td> | |
| <td><code>false</code></td> | |
| <td>Live order fill / exit confirmations from exchange sync</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <pre><code class="js"><span class="hl-6">// config/notification.config.ts</span><br/><span class="hl-4">export</span><span class="hl-1"> </span><span class="hl-4">default</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">signal:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">risk:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">info:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">breakeven:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">common_error:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">critical_error:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">validation_error:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">strategy_commit:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">partial_loss:</span><span class="hl-1"> </span><span class="hl-3">false</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">partial_profit:</span><span class="hl-1"> </span><span class="hl-3">false</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">signal_sync:</span><span class="hl-1"> </span><span class="hl-3">false</span><span class="hl-1">,</span><br/><span class="hl-1">};</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="telegram-notifications---telegram" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Telegram Notifications (<code>--telegram</code>)<a href="#telegram-notifications---telegram" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Sends formatted HTML messages with 1m / 15m / 1h price charts to your Telegram channel for every position event: opened, closed, scheduled, cancelled, risk rejection, partial profit/loss, trailing stop/take, and breakeven.</p> | |
| <p>Requires <code>CC_TELEGRAM_TOKEN</code> and <code>CC_TELEGRAM_CHANNEL</code> in your environment.</p> | |
| <a id="telegram-message-adapter-telegramconfig" class="tsd-anchor"></a><h4 class="tsd-anchor-link">Telegram Message Adapter (<code>telegram.config</code>)<a href="#telegram-message-adapter-telegramconfig" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h4><p>By default messages are rendered from Mustache templates (<code>template/*.mustache</code>). To override rendering programmatically, create a <code>config/telegram.config</code> file and export an object with any subset of <code>get*Markdown</code> methods. Each method receives the event payload and must return a <code>Promise<string></code> with the Markdown message body.</p> | |
| <p>Resolution order is the same as other configs (strategy dir β project root β package default).</p> | |
| <pre><code class="ts"><span class="hl-6">// config/telegram.config.ts</span><br/><span class="hl-4">import</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">IStrategyTickResultOpened</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">IStrategyTickResultClosed</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">RiskContract</span><span class="hl-1">,</span><br/><span class="hl-1">} </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"backtest-kit"</span><span class="hl-1">;</span><br/><br/><span class="hl-4">export</span><span class="hl-1"> </span><span class="hl-4">default</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">getOpenedMarkdown</span><span class="hl-1">(</span><span class="hl-5">event</span><span class="hl-1">: </span><span class="hl-11">IStrategyTickResultOpened</span><span class="hl-1">): </span><span class="hl-11">Promise</span><span class="hl-1"><</span><span class="hl-11">string</span><span class="hl-1">> {</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-2">`**Opened** </span><span class="hl-3">${</span><span class="hl-5">event</span><span class="hl-9">.</span><span class="hl-5">symbol</span><span class="hl-3">}</span><span class="hl-2"> at </span><span class="hl-3">${</span><span class="hl-5">event</span><span class="hl-9">.</span><span class="hl-5">priceOpen</span><span class="hl-3">}</span><span class="hl-2">`</span><span class="hl-1">;</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">getClosedMarkdown</span><span class="hl-1">(</span><span class="hl-5">event</span><span class="hl-1">: </span><span class="hl-11">IStrategyTickResultClosed</span><span class="hl-1">): </span><span class="hl-11">Promise</span><span class="hl-1"><</span><span class="hl-11">string</span><span class="hl-1">> {</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-2">`**Closed** </span><span class="hl-3">${</span><span class="hl-5">event</span><span class="hl-9">.</span><span class="hl-5">symbol</span><span class="hl-3">}</span><span class="hl-2"> at </span><span class="hl-3">${</span><span class="hl-5">event</span><span class="hl-9">.</span><span class="hl-5">priceClosed</span><span class="hl-3">}</span><span class="hl-2">`</span><span class="hl-1">;</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">getRiskMarkdown</span><span class="hl-1">(</span><span class="hl-5">event</span><span class="hl-1">: </span><span class="hl-11">RiskContract</span><span class="hl-1">): </span><span class="hl-11">Promise</span><span class="hl-1"><</span><span class="hl-11">string</span><span class="hl-1">> {</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-2">`**Risk rejected** </span><span class="hl-3">${</span><span class="hl-5">event</span><span class="hl-9">.</span><span class="hl-5">symbol</span><span class="hl-3">}</span><span class="hl-2">`</span><span class="hl-1">;</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">};</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>All methods are optional β unimplemented ones fall back to the Mustache template.</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Method</th> | |
| <th>Event type</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>getOpenedMarkdown</code></td> | |
| <td><code>IStrategyTickResultOpened</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getClosedMarkdown</code></td> | |
| <td><code>IStrategyTickResultClosed</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getScheduledMarkdown</code></td> | |
| <td><code>IStrategyTickResultScheduled</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getCancelledMarkdown</code></td> | |
| <td><code>IStrategyTickResultCancelled</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getRiskMarkdown</code></td> | |
| <td><code>RiskContract</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getPartialProfitMarkdown</code></td> | |
| <td><code>PartialProfitCommit</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getPartialLossMarkdown</code></td> | |
| <td><code>PartialLossCommit</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getBreakevenMarkdown</code></td> | |
| <td><code>BreakevenCommit</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getTrailingTakeMarkdown</code></td> | |
| <td><code>TrailingTakeCommit</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getTrailingStopMarkdown</code></td> | |
| <td><code>TrailingStopCommit</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getAverageBuyMarkdown</code></td> | |
| <td><code>AverageBuyCommit</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getSignalOpenMarkdown</code></td> | |
| <td><code>SignalOpenContract</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getSignalCloseMarkdown</code></td> | |
| <td><code>SignalCloseContract</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getCancelScheduledMarkdown</code></td> | |
| <td><code>CancelScheduledCommit</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getClosePendingMarkdown</code></td> | |
| <td><code>ClosePendingCommit</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>getSignalInfoMarkdown</code></td> | |
| <td><code>SignalInfoContract</code></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="π§©-module-hooks-broker-adapter" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π§© Module Hooks (Broker Adapter)<a href="#π§©-module-hooks-broker-adapter" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The CLI supports <strong>mode-specific module files</strong> that are loaded as side-effect imports before the strategy starts. Each file is expected to call <code>Broker.useBrokerAdapter()</code> from <code>backtest-kit</code> to register a broker adapter.</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Command Line Args</th> | |
| <th>Module file</th> | |
| <th>Loaded before</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>--live</code></td> | |
| <td><code>./modules/live.module.mjs</code></td> | |
| <td><code>Live.background()</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>--paper</code></td> | |
| <td><code>./modules/paper.module.mjs</code></td> | |
| <td><code>Live.background()</code> (paper)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--backtest</code></td> | |
| <td><code>./modules/backtest.module.mjs</code></td> | |
| <td><code>Backtest.background()</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>--walker</code></td> | |
| <td><code>./modules/walker.module.mjs</code></td> | |
| <td><code>Walker.background()</code></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <blockquote> | |
| <p>File is resolved relative to <code>cwd</code> (the strategy directory). All of <code>.mjs</code>, <code>.cjs</code>, <code>.ts</code> extensions are tried automatically. Missing module is a soft warning β not an error.</p> | |
| </blockquote> | |
| <a id="how-it-works-2" class="tsd-anchor"></a><h3 class="tsd-anchor-link">How It Works<a href="#how-it-works-2" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>The module file is a side-effect import. When the CLI loads it, your code runs and registers the adapter. From that point on, <code>backtest-kit</code> intercepts every trade-mutating call through the adapter <strong>before</strong> updating internal state β if the adapter throws, the position state is never changed.</p> | |
| <pre><code class="javascript"><span class="hl-6">// live.module.mjs</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">Broker</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'backtest-kit'</span><span class="hl-1">;</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">myExchange</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'./exchange.mjs'</span><span class="hl-1">;</span><br/><br/><span class="hl-3">class</span><span class="hl-1"> </span><span class="hl-11">MyBroker</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">onSignalOpenCommit</span><span class="hl-1">({ </span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">priceOpen</span><span class="hl-1">, </span><span class="hl-5">direction</span><span class="hl-1"> }) {</span><br/><span class="hl-1"> </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">myExchange</span><span class="hl-1">.</span><span class="hl-0">openPosition</span><span class="hl-1">(</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">direction</span><span class="hl-1">, </span><span class="hl-5">priceOpen</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">onSignalCloseCommit</span><span class="hl-1">({ </span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">priceClosed</span><span class="hl-1"> }) {</span><br/><span class="hl-1"> </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">myExchange</span><span class="hl-1">.</span><span class="hl-0">closePosition</span><span class="hl-1">(</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">priceClosed</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">onPartialProfitCommit</span><span class="hl-1">({ </span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">cost</span><span class="hl-1">, </span><span class="hl-5">currentPrice</span><span class="hl-1"> }) {</span><br/><span class="hl-1"> </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">myExchange</span><span class="hl-1">.</span><span class="hl-0">createOrder</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">symbol</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">side:</span><span class="hl-1"> </span><span class="hl-2">'sell'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">quantity:</span><span class="hl-1"> </span><span class="hl-5">cost</span><span class="hl-1"> / </span><span class="hl-5">currentPrice</span><span class="hl-1">,</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">onAverageBuyCommit</span><span class="hl-1">({ </span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">cost</span><span class="hl-1">, </span><span class="hl-5">currentPrice</span><span class="hl-1"> }) {</span><br/><span class="hl-1"> </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">myExchange</span><span class="hl-1">.</span><span class="hl-0">createOrder</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">symbol</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">side:</span><span class="hl-1"> </span><span class="hl-2">'buy'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">quantity:</span><span class="hl-1"> </span><span class="hl-5">cost</span><span class="hl-1"> / </span><span class="hl-5">currentPrice</span><span class="hl-1">,</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-5">Broker</span><span class="hl-1">.</span><span class="hl-0">useBrokerAdapter</span><span class="hl-1">(</span><span class="hl-5">MyBroker</span><span class="hl-1">);</span><br/><br/><span class="hl-5">Broker</span><span class="hl-1">.</span><span class="hl-0">enable</span><span class="hl-1">();</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="available-broker-hooks" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Available Broker Hooks<a href="#available-broker-hooks" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Method</th> | |
| <th>Payload type</th> | |
| <th>Triggered on</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>onSignalOpenCommit</code></td> | |
| <td><code>BrokerSignalOpenPayload</code></td> | |
| <td>Position activation</td> | |
| </tr> | |
| <tr> | |
| <td><code>onSignalCloseCommit</code></td> | |
| <td><code>BrokerSignalClosePayload</code></td> | |
| <td>SL / TP / manual close</td> | |
| </tr> | |
| <tr> | |
| <td><code>onPartialProfitCommit</code></td> | |
| <td><code>BrokerPartialProfitPayload</code></td> | |
| <td>PP</td> | |
| </tr> | |
| <tr> | |
| <td><code>onPartialLossCommit</code></td> | |
| <td><code>BrokerPartialLossPayload</code></td> | |
| <td>PL</td> | |
| </tr> | |
| <tr> | |
| <td><code>onTrailingStopCommit</code></td> | |
| <td><code>BrokerTrailingStopPayload</code></td> | |
| <td>SL adjustment</td> | |
| </tr> | |
| <tr> | |
| <td><code>onTrailingTakeCommit</code></td> | |
| <td><code>BrokerTrailingTakePayload</code></td> | |
| <td>TP adjustment</td> | |
| </tr> | |
| <tr> | |
| <td><code>onBreakevenCommit</code></td> | |
| <td><code>BrokerBreakevenPayload</code></td> | |
| <td>SL moved to entry</td> | |
| </tr> | |
| <tr> | |
| <td><code>onAverageBuyCommit</code></td> | |
| <td><code>BrokerAverageBuyPayload</code></td> | |
| <td>DCA entry</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p>All methods are optional. Unimplemented hooks are silently skipped. In backtest mode all broker calls are skipped automatically β no adapter code runs during backtests.</p> | |
| <a id="typescript" class="tsd-anchor"></a><h3 class="tsd-anchor-link">TypeScript<a href="#typescript" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">Broker</span><span class="hl-1">, </span><span class="hl-5">IBroker</span><span class="hl-1">, </span><span class="hl-5">BrokerSignalOpenPayload</span><span class="hl-1">, </span><span class="hl-5">BrokerSignalClosePayload</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'backtest-kit'</span><span class="hl-1">;</span><br/><br/><span class="hl-3">class</span><span class="hl-1"> </span><span class="hl-11">MyBroker</span><span class="hl-1"> </span><span class="hl-3">implements</span><span class="hl-1"> </span><span class="hl-11">Partial</span><span class="hl-1"><</span><span class="hl-11">IBroker</span><span class="hl-1">> {</span><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">onSignalOpenCommit</span><span class="hl-1">(</span><span class="hl-5">payload</span><span class="hl-1">: </span><span class="hl-11">BrokerSignalOpenPayload</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-6">// place open order on exchange</span><br/><span class="hl-1"> }</span><br/><br/><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> </span><span class="hl-0">onSignalCloseCommit</span><span class="hl-1">(</span><span class="hl-5">payload</span><span class="hl-1">: </span><span class="hl-11">BrokerSignalClosePayload</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-6">// place close order on exchange</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-5">Broker</span><span class="hl-1">.</span><span class="hl-0">useBrokerAdapter</span><span class="hl-1">(</span><span class="hl-5">MyBroker</span><span class="hl-1">);</span><br/><br/><span class="hl-5">Broker</span><span class="hl-1">.</span><span class="hl-0">enable</span><span class="hl-1">();</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π-import-aliases-aliasmodule" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π Import Aliases (<code>alias.module</code>)<a href="#π-import-aliases-aliasmodule" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> lets you override any nodejs module import β without touching the strategy code. Drop a <code>config/alias.module</code> file in your project root and export a mapping from module name to replacement module.</p> | |
| <p>The alias table is loaded once (on the first <code>import</code> call) from <code>{projectRoot}/config/alias.module</code> and applied globally to every subsequent module load via <code>require</code>/ <code>import</code>.</p> | |
| <p><strong>Use cases:</strong></p> | |
| <ul> | |
| <li>Replace a heavy dependency with a lighter stub for backtesting</li> | |
| <li>Swap any external api for a mock during CI runs</li> | |
| </ul> | |
| <pre><code class="ts"><span class="hl-6">// config/alias.module.ts β named export</span><br/><span class="hl-4">export</span><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">ccxt</span><span class="hl-1"> = </span><span class="hl-0">require</span><span class="hl-1">(</span><span class="hl-2">"./stubs/ccxt.stub.cjs"</span><span class="hl-1">);</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="js"><span class="hl-6">// config/alias.module.cjs β default export</span><br/><span class="hl-11">module</span><span class="hl-1">.</span><span class="hl-11">exports</span><span class="hl-1"> = {</span><br/><span class="hl-1"> </span><span class="hl-5">ccxt:</span><span class="hl-1"> </span><span class="hl-0">require</span><span class="hl-1">(</span><span class="hl-2">"./stubs/ccxt.stub.cjs"</span><span class="hl-1">),</span><br/><span class="hl-1">};</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="js"><span class="hl-6">// config/alias.module.mjs β default export</span><br/><span class="hl-4">import</span><span class="hl-1"> </span><span class="hl-5">ccxtStub</span><span class="hl-1"> </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"./stubs/ccxt.stub.mjs"</span><span class="hl-1">;</span><br/><br/><span class="hl-4">export</span><span class="hl-1"> </span><span class="hl-4">default</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">ccxt:</span><span class="hl-1"> </span><span class="hl-5">ccxtStub</span><span class="hl-1">,</span><br/><span class="hl-1">};</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p><strong>How it works:</strong> when strategy code calls <code>require("ccxt")</code>, the loader checks <code>IMPORT_ALIAS</code> first. If a key matches, the mapped value is returned instead of the real module β no monkey-patching of <code>node_modules</code> needed.</p> | |
| <p><strong>Important:</strong> It is <strong>not</strong> per-strategy β it applies to all modules loaded in the current process.</p> | |
| <a id="π¦-supported-entry-point-formats" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π¦ Supported Entry Point Formats<a href="#π¦-supported-entry-point-formats" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> automatically detects the format of your strategy file and loads it with the appropriate runtime β no flags or configuration required.</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Format</th> | |
| <th>Extension</th> | |
| <th>Runtime</th> | |
| <th>Use Case</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><strong>TypeScript</strong></td> | |
| <td><code>.ts</code></td> | |
| <td><a href="https://tsx.is/"><code>tsx</code></a> via <code>tsImport()</code></td> | |
| <td>TypeScript strategies with cross-imports (ESM β CJS)</td> | |
| </tr> | |
| <tr> | |
| <td><strong>ES Module</strong></td> | |
| <td><code>.mjs</code></td> | |
| <td>Native <code>import()</code></td> | |
| <td>Modern JavaScript with top-level <code>await</code> and ESM syntax</td> | |
| </tr> | |
| <tr> | |
| <td><strong>CommonJS</strong></td> | |
| <td><code>.cjs</code></td> | |
| <td>Native <code>require()</code></td> | |
| <td>Legacy or dual-package strategies</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="typescript-ts" class="tsd-anchor"></a><h3 class="tsd-anchor-link">TypeScript (<code>.ts</code>)<a href="#typescript-ts" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Run TypeScript strategy files directly β no <code>tsc</code> compilation step needed. Powered by <code>tsx</code>, which handles cross-format imports transparently:</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest ./src/index.ts"</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-16">"dependencies"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"@backtest-kit/cli"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest-kit"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-16">"tsx"</span><span class="hl-1">: </span><span class="hl-2">"latest"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="es-module-mjs" class="tsd-anchor"></a><h3 class="tsd-anchor-link">ES Module (<code>.mjs</code>)<a href="#es-module-mjs" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Standard ESM format. Supports top-level <code>await</code>, named exports, and <code>import</code> syntax:</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest ./src/index.mjs"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="commonjs-cjs" class="tsd-anchor"></a><h3 class="tsd-anchor-link">CommonJS (<code>.cjs</code>)<a href="#commonjs-cjs" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>For projects that compile to or use CommonJS. Loaded via <code>require()</code>:</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"backtest"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest ./dist/index.cjs"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π²-running-local-pinescript-indicators" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π² Running Local PineScript Indicators<a href="#π²-running-local-pinescript-indicators" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> can execute any local <code>.pine</code> file against a real exchange and print the results as a Markdown table β no TradingView account required.</p> | |
| <a id="cli-flags" class="tsd-anchor"></a><h3 class="tsd-anchor-link">CLI Flags<a href="#cli-flags" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Flag</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>--pine</code></td> | |
| <td>boolean</td> | |
| <td>Enable PineScript execution mode</td> | |
| </tr> | |
| <tr> | |
| <td><code>--symbol</code></td> | |
| <td>string</td> | |
| <td>Trading pair (default: <code>"BTCUSDT"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--timeframe</code></td> | |
| <td>string</td> | |
| <td>Candle interval (default: <code>"15m"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--limit</code></td> | |
| <td>string</td> | |
| <td>Number of candles to fetch (default: <code>250</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--when</code></td> | |
| <td>string</td> | |
| <td>End date for candle window β ISO 8601 or Unix ms (default: now)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--exchange</code></td> | |
| <td>string</td> | |
| <td>Exchange name (default: first registered, falls back to CCXT Binance)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--output</code></td> | |
| <td>string</td> | |
| <td>Output file base name without extension (default: <code>.pine</code> file name)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--json</code></td> | |
| <td>boolean</td> | |
| <td>Write plots as a JSON array to <code><pine-dir>/dump/{output}.json</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>--jsonl</code></td> | |
| <td>boolean</td> | |
| <td>Write plots as JSONL (one row per line) to <code><pine-dir>/dump/{output}.jsonl</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>--markdown</code></td> | |
| <td>boolean</td> | |
| <td>Write Markdown table to <code><pine-dir>/dump/{output}.md</code></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p><strong>Important:</strong> <code>limit</code> must cover indicator warmup bars β rows before warmup completes will show <code>N/A</code></p> | |
| <p><strong>Positional argument:</strong> path to the <code>.pine</code> file.</p> | |
| <a id="exchange-via-pinemodule" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Exchange via <code>pine.module</code><a href="#exchange-via-pinemodule" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>By default the CLI registers CCXT Binance automatically. To use a different exchange β or to configure API keys, custom rate limits, or a non-spot market β create a <code>modules/pine.module.ts</code> file. The CLI loads it automatically before running the script.</p> | |
| <p>The CLI looks for <code>modules/pine.module</code> in two locations (first match wins):</p> | |
| <ol> | |
| <li><strong>Next to the <code>.pine</code> file</strong> β <code><pine-file-dir>/modules/pine.module.ts</code></li> | |
| <li><strong>Project root</strong> β <code><cwd>/modules/pine.module.ts</code></li> | |
| </ol> | |
| <pre><code><span class="hl-5">my</span><span class="hl-1">-</span><span class="hl-5">project</span><span class="hl-1">/</span><br/><span class="hl-1">βββ </span><span class="hl-5">math</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">impulse_trend_15m</span><span class="hl-1">.</span><span class="hl-5">pine</span><span class="hl-1"> β </span><span class="hl-5">indicator</span><br/><span class="hl-1">β βββ </span><span class="hl-5">modules</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">pine</span><span class="hl-1">.</span><span class="hl-5">module</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> β </span><span class="hl-5">loaded</span><span class="hl-1"> </span><span class="hl-0">first</span><span class="hl-1"> (</span><span class="hl-5">next</span><span class="hl-1"> </span><span class="hl-5">to</span><span class="hl-1"> .</span><span class="hl-5">pine</span><span class="hl-1"> </span><span class="hl-5">file</span><span class="hl-1">)</span><br/><span class="hl-1">βββ </span><span class="hl-5">modules</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">pine</span><span class="hl-1">.</span><span class="hl-5">module</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> β </span><span class="hl-0">fallback</span><span class="hl-1"> (</span><span class="hl-5">project</span><span class="hl-1"> </span><span class="hl-5">root</span><span class="hl-1">)</span><br/><span class="hl-1">βββ </span><span class="hl-5">package</span><span class="hl-1">.</span><span class="hl-5">json</span> | |
| </code><button>Copy</button></pre> | |
| <p>Inside <code>pine.module.ts</code> call <code>addExchangeSchema</code> from <code>backtest-kit</code> and give the exchange a name:</p> | |
| <pre><code class="typescript"><span class="hl-6">// modules/pine.module.ts</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">addExchangeSchema</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"backtest-kit"</span><span class="hl-1">;</span><br/><span class="hl-4">import</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1"> </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"ccxt"</span><span class="hl-1">;</span><br/><br/><span class="hl-0">addExchangeSchema</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">exchangeName:</span><span class="hl-1"> </span><span class="hl-2">"my-exchange"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">getCandles</span><span class="hl-5">:</span><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">, </span><span class="hl-5">limit</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">exchange</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1">.</span><span class="hl-0">bybit</span><span class="hl-1">({ </span><span class="hl-5">enableRateLimit:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">ohlcv</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">exchange</span><span class="hl-1">.</span><span class="hl-0">fetchOHLCV</span><span class="hl-1">(</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">.</span><span class="hl-0">getTime</span><span class="hl-1">(), </span><span class="hl-5">limit</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-5">ohlcv</span><span class="hl-1">.</span><span class="hl-0">map</span><span class="hl-1">(([</span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">]) </span><span class="hl-3">=></span><span class="hl-1"> ({</span><br/><span class="hl-1"> </span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">,</span><br/><span class="hl-1"> }));</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-0">formatPrice</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">price</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">price</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">2</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-0">formatQuantity</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">quantity</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">quantity</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">8</span><span class="hl-1">),</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="environment-variables-env" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Environment variables (<code>.env</code>)<a href="#environment-variables-env" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Before loading <code>pine.module</code>, the CLI loads <code>.env</code> files in the same order as for strategy modules β project root first, then the <code>.pine</code> file directory (overrides root):</p> | |
| <pre><code><span class="hl-5">my</span><span class="hl-1">-</span><span class="hl-5">project</span><span class="hl-1">/</span><br/><span class="hl-1">βββ </span><span class="hl-5">math</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ .</span><span class="hl-5">env</span><span class="hl-1"> β </span><span class="hl-5">loaded</span><span class="hl-1"> </span><span class="hl-0">second</span><span class="hl-1"> (</span><span class="hl-5">overrides</span><span class="hl-1"> </span><span class="hl-5">root</span><span class="hl-1">)</span><br/><span class="hl-1">β βββ </span><span class="hl-5">impulse_trend_15m</span><span class="hl-1">.</span><span class="hl-5">pine</span><br/><span class="hl-1">βββ .</span><span class="hl-5">env</span><span class="hl-1"> β </span><span class="hl-5">loaded</span><span class="hl-1"> </span><span class="hl-5">first</span><br/><span class="hl-1">βββ </span><span class="hl-5">package</span><span class="hl-1">.</span><span class="hl-5">json</span> | |
| </code><button>Copy</button></pre> | |
| <p>Use this to store API keys without hardcoding them:</p> | |
| <pre><code class="env"># .env | |
| BYBIT_API_KEY=xxx | |
| BYBIT_API_SECRET=yyy | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="typescript"><span class="hl-6">// modules/pine.module.ts</span><br/><span class="hl-0">addExchangeSchema</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">exchangeName:</span><span class="hl-1"> </span><span class="hl-2">"my-exchange"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">getCandles</span><span class="hl-5">:</span><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">, </span><span class="hl-5">limit</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">exchange</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1">.</span><span class="hl-0">bybit</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">apiKey:</span><span class="hl-1"> </span><span class="hl-5">process</span><span class="hl-1">.</span><span class="hl-5">env</span><span class="hl-1">.</span><span class="hl-8">BYBIT_API_KEY</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">secret:</span><span class="hl-1"> </span><span class="hl-5">process</span><span class="hl-1">.</span><span class="hl-5">env</span><span class="hl-1">.</span><span class="hl-8">BYBIT_API_SECRET</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">enableRateLimit:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-6">// ...</span><br/><span class="hl-1"> },</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Then run:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--pine</span><span class="hl-1"> </span><span class="hl-2">./math/impulse_trend_15m.pine</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--exchange</span><span class="hl-1"> </span><span class="hl-2">my-exchange</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--timeframe</span><span class="hl-1"> </span><span class="hl-2">15m</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--limit</span><span class="hl-1"> </span><span class="hl-7">180</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--when</span><span class="hl-1"> </span><span class="hl-2">"2025-09-24T12:00:00.000Z"</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Or add it to <code>package.json</code>:</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"pine"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --pine ./math/impulse_trend_15m.pine --symbol BTCUSDT --timeframe 15m --limit 180"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">pine</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="pinescript-requirements" class="tsd-anchor"></a><h3 class="tsd-anchor-link">PineScript Requirements<a href="#pinescript-requirements" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>The CLI reads all <code>plot()</code> calls that use <code>display=display.data_window</code> as output columns. Every other <code>plot()</code> is ignored. Name each output plot explicitly:</p> | |
| <pre><code class="pine">//@version=5 | |
| indicator("MyIndicator", overlay=true) | |
| // ... computation ... | |
| plot(close, "Close", display=display.data_window) | |
| plot(position, "Position", display=display.data_window) | |
| </code><button type="button">Copy</button></pre> | |
| <p>The column names in the output Markdown table are taken directly from those plot names β no manual schema definition needed.</p> | |
| <a id="output" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Output<a href="#output" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>The CLI prints a Markdown table to stdout:</p> | |
| <pre><code><span class="hl-1"># </span><span class="hl-5">PineScript</span><span class="hl-1"> </span><span class="hl-5">Technical</span><span class="hl-1"> </span><span class="hl-5">Analysis</span><span class="hl-1"> </span><span class="hl-5">Dump</span><br/><br/><span class="hl-1">**</span><span class="hl-5">Signal</span><span class="hl-1"> </span><span class="hl-8">ID</span><span class="hl-1">**: </span><span class="hl-8">CLI</span><span class="hl-1"> </span><span class="hl-5">execution</span><span class="hl-1"> </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">09</span><span class="hl-1">-24</span><span class="hl-10">T12</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><br/><br/><span class="hl-1">| </span><span class="hl-5">Close</span><span class="hl-1"> | </span><span class="hl-5">Position</span><span class="hl-1"> | </span><span class="hl-5">timestamp</span><span class="hl-1"> |</span><br/><span class="hl-1">| --- | --- | --- |</span><br/><span class="hl-1">| </span><span class="hl-7">112871.28</span><span class="hl-1"> | -</span><span class="hl-7">1.0000</span><span class="hl-1"> | </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">09</span><span class="hl-1">-22</span><span class="hl-10">T15</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><span class="hl-1"> |</span><br/><span class="hl-1">| </span><span class="hl-7">112666.69</span><span class="hl-1"> | -</span><span class="hl-7">1.0000</span><span class="hl-1"> | </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">09</span><span class="hl-1">-22</span><span class="hl-10">T15</span><span class="hl-1">:</span><span class="hl-7">15</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><span class="hl-1"> |</span><br/><span class="hl-1">| </span><span class="hl-7">112736.00</span><span class="hl-1"> | </span><span class="hl-7">0.0000</span><span class="hl-1"> | </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">09</span><span class="hl-1">-22</span><span class="hl-10">T18</span><span class="hl-1">:</span><span class="hl-7">30</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><span class="hl-1"> |</span><br/><span class="hl-1">| </span><span class="hl-7">112653.90</span><span class="hl-1"> | </span><span class="hl-7">1.0000</span><span class="hl-1"> | </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">09</span><span class="hl-1">-22</span><span class="hl-10">T22</span><span class="hl-1">:</span><span class="hl-7">15</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><span class="hl-1"> |</span> | |
| </code><button>Copy</button></pre> | |
| <p>Save to <code>./math/dump/impulse_trend_15m.md</code> (uses <code>.pine</code> file name automatically, dump is created next to the <code>.pine</code> file):</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--pine</span><span class="hl-1"> </span><span class="hl-2">./math/impulse_trend_15m.pine</span><span class="hl-1"> </span><span class="hl-3">--markdown</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Override the output name with <code>--output</code>:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--pine</span><span class="hl-1"> </span><span class="hl-2">./math/impulse_trend_15m.pine</span><span class="hl-1"> </span><span class="hl-3">--jsonl</span><span class="hl-1"> </span><span class="hl-3">--output</span><span class="hl-1"> </span><span class="hl-2">feb2026_bb</span><br/><span class="hl-6"># β ./math/dump/feb2026_bb.jsonl</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Print to stdout (no flag):</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--pine</span><span class="hl-1"> </span><span class="hl-2">./math/impulse_trend_15m.pine</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π¨-visual-pine-script-editor" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π¨ Visual Pine Script Editor<a href="#π¨-visual-pine-script-editor" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><img src="https://raw.githubusercontent.com/tripolskypetr/backtest-kit/HEAD/assets/screenshots/screenshot32.png" alt="pine"></p> | |
| <p><code>@backtest-kit/cli</code> ships a browser-based Pine Script editor powered by <code>@backtest-kit/ui</code>. It lets you write, run, and iterate on indicators interactively β with a live chart that updates as you hit <strong>βΆ Run</strong></p> | |
| <a id="usage" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Usage<a href="#usage" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--editor</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>The CLI will:</p> | |
| <ol> | |
| <li>Load <code>./modules/editor.module</code> (if it exists) β use it to register your exchange schema, identical to <code>pine.module</code></li> | |
| <li>Start the <code>@backtest-kit/ui</code> server on <code>http://localhost:60050</code> (or <code>CC_WWWROOT_PORT</code>)</li> | |
| <li>Open <code>http://localhost:{CC_WWWROOT_PORT}?pine=1</code> automatically in your default browser</li> | |
| </ol> | |
| <p>Press <strong>Ctrl+C</strong> to stop the server.</p> | |
| <a id="exchange-via-editormodule" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Exchange via <code>editor.module</code><a href="#exchange-via-editormodule" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Drop a <code>modules/editor.module.ts</code> next to your project to register the exchange that the editor's candle provider will use:</p> | |
| <pre><code class="typescript"><span class="hl-6">// modules/editor.module.ts</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">addExchangeSchema</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"backtest-kit"</span><span class="hl-1">;</span><br/><span class="hl-4">import</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1"> </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"ccxt"</span><span class="hl-1">;</span><br/><br/><span class="hl-0">addExchangeSchema</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">exchangeName:</span><span class="hl-1"> </span><span class="hl-2">"my-exchange"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">getCandles</span><span class="hl-5">:</span><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">, </span><span class="hl-5">limit</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">exchange</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1">.</span><span class="hl-0">bybit</span><span class="hl-1">({ </span><span class="hl-5">enableRateLimit:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">ohlcv</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">exchange</span><span class="hl-1">.</span><span class="hl-0">fetchOHLCV</span><span class="hl-1">(</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">.</span><span class="hl-0">getTime</span><span class="hl-1">(), </span><span class="hl-5">limit</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-5">ohlcv</span><span class="hl-1">.</span><span class="hl-0">map</span><span class="hl-1">(([</span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">]) </span><span class="hl-3">=></span><span class="hl-1"> ({</span><br/><span class="hl-1"> </span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">,</span><br/><span class="hl-1"> }));</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-0">formatPrice</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">price</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">price</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">2</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-0">formatQuantity</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">quantity</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">quantity</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">8</span><span class="hl-1">),</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="environment-variables" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Environment Variables<a href="#environment-variables" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Variable</th> | |
| <th>Default</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>CC_WWWROOT_HOST</code></td> | |
| <td><code>0.0.0.0</code></td> | |
| <td>UI server bind address</td> | |
| </tr> | |
| <tr> | |
| <td><code>CC_WWWROOT_PORT</code></td> | |
| <td><code>60050</code></td> | |
| <td>UI server port</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="packagejson-script" class="tsd-anchor"></a><h3 class="tsd-anchor-link"><code>package.json</code> script<a href="#packagejson-script" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"editor"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --editor"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">editor</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="πΎ-dumping-raw-candles" class="tsd-anchor"></a><h2 class="tsd-anchor-link">πΎ Dumping Raw Candles<a href="#πΎ-dumping-raw-candles" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> can fetch raw OHLCV candles from any registered exchange and save them to a file β no strategy file required.</p> | |
| <a id="cli-flags-1" class="tsd-anchor"></a><h3 class="tsd-anchor-link">CLI Flags<a href="#cli-flags-1" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Flag</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>--dump</code></td> | |
| <td>boolean</td> | |
| <td>Enable candle dump mode</td> | |
| </tr> | |
| <tr> | |
| <td><code>--symbol</code></td> | |
| <td>string</td> | |
| <td>Trading pair (default: <code>"BTCUSDT"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--timeframe</code></td> | |
| <td>string</td> | |
| <td>Candle interval (default: <code>"15m"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--limit</code></td> | |
| <td>string</td> | |
| <td>Number of candles to fetch (default: <code>250</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--when</code></td> | |
| <td>string</td> | |
| <td>End date for candle window β ISO 8601 or Unix ms (default: now)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--exchange</code></td> | |
| <td>string</td> | |
| <td>Exchange name (default: first registered, falls back to CCXT Binance)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--output</code></td> | |
| <td>string</td> | |
| <td>Output file base name without extension (default: <code>{SYMBOL}_{LIMIT}_{TIMEFRAME}_{TIMESTAMP}</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--json</code></td> | |
| <td>boolean</td> | |
| <td>Write candles as a JSON array to <code>./dump/{output}.json</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>--jsonl</code></td> | |
| <td>boolean</td> | |
| <td>Write candles as JSONL (one row per line) to <code>./dump/{output}.jsonl</code></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p>The <code>dump/</code> directory is created in the current working directory (where the CLI is invoked from).</p> | |
| <a id="exchange-via-dumpmodule" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Exchange via <code>dump.module</code><a href="#exchange-via-dumpmodule" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>By default the CLI registers CCXT Binance automatically. To use a different exchange β or to configure API keys, custom rate limits, or a non-spot market β create a <code>modules/dump.module.ts</code> file. The CLI loads it automatically before fetching candles.</p> | |
| <p>The CLI looks for <code>modules/dump.module</code> in the current working directory</p> | |
| <pre><code><span class="hl-5">my</span><span class="hl-1">-</span><span class="hl-5">project</span><span class="hl-1">/</span><br/><span class="hl-1">βββ </span><span class="hl-5">modules</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">dump</span><span class="hl-1">.</span><span class="hl-5">module</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> β </span><span class="hl-5">exchange</span><span class="hl-1"> </span><span class="hl-5">registration</span><br/><span class="hl-1">βββ </span><span class="hl-5">dump</span><span class="hl-1">/ β </span><span class="hl-5">auto</span><span class="hl-1">-</span><span class="hl-10">created</span><span class="hl-1">: </span><span class="hl-5">candle</span><span class="hl-1"> </span><span class="hl-5">output</span><span class="hl-1"> </span><span class="hl-5">files</span><br/><span class="hl-1">βββ </span><span class="hl-5">package</span><span class="hl-1">.</span><span class="hl-5">json</span> | |
| </code><button>Copy</button></pre> | |
| <p>Inside <code>dump.module.ts</code> call <code>addExchangeSchema</code> from <code>backtest-kit</code>:</p> | |
| <pre><code class="typescript"><span class="hl-6">// modules/dump.module.ts</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">addExchangeSchema</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"backtest-kit"</span><span class="hl-1">;</span><br/><span class="hl-4">import</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1"> </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"ccxt"</span><span class="hl-1">;</span><br/><br/><span class="hl-0">addExchangeSchema</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">exchangeName:</span><span class="hl-1"> </span><span class="hl-2">"my-exchange"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">getCandles</span><span class="hl-5">:</span><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">, </span><span class="hl-5">limit</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">exchange</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1">.</span><span class="hl-0">bybit</span><span class="hl-1">({ </span><span class="hl-5">enableRateLimit:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">ohlcv</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">exchange</span><span class="hl-1">.</span><span class="hl-0">fetchOHLCV</span><span class="hl-1">(</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">.</span><span class="hl-0">getTime</span><span class="hl-1">(), </span><span class="hl-5">limit</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-5">ohlcv</span><span class="hl-1">.</span><span class="hl-0">map</span><span class="hl-1">(([</span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">]) </span><span class="hl-3">=></span><span class="hl-1"> ({</span><br/><span class="hl-1"> </span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">,</span><br/><span class="hl-1"> }));</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-0">formatPrice</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">price</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">price</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">2</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-0">formatQuantity</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">quantity</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">quantity</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">8</span><span class="hl-1">),</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="output-1" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Output<a href="#output-1" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Each candle row contains OHLCV fields. Print to stdout:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--dump</span><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-3">--timeframe</span><span class="hl-1"> </span><span class="hl-2">15m</span><span class="hl-1"> </span><span class="hl-3">--limit</span><span class="hl-1"> </span><span class="hl-7">100</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Save to <code>./dump/BTCUSDT_100_15m_{timestamp}.jsonl</code>:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--dump</span><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-3">--timeframe</span><span class="hl-1"> </span><span class="hl-2">15m</span><span class="hl-1"> </span><span class="hl-3">--limit</span><span class="hl-1"> </span><span class="hl-7">100</span><span class="hl-1"> </span><span class="hl-3">--jsonl</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Fetch candles up to a specific date with <code>--when</code> and override the file name with <code>--output</code>:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--dump</span><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-3">--timeframe</span><span class="hl-1"> </span><span class="hl-2">15m</span><span class="hl-1"> </span><span class="hl-3">--limit</span><span class="hl-1"> </span><span class="hl-7">500</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--when</span><span class="hl-1"> </span><span class="hl-2">"2026-02-28T00:00:00.000Z"</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--jsonl</span><span class="hl-1"> </span><span class="hl-3">--output</span><span class="hl-1"> </span><span class="hl-2">feb2026_btc</span><br/><span class="hl-6"># β ./dump/feb2026_btc.jsonl</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Or add it to <code>package.json</code>:</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"dump"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --dump --symbol BTCUSDT --timeframe 15m --limit 500 --jsonl"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--dump</span><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-3">--timeframe</span><span class="hl-1"> </span><span class="hl-2">15m</span><span class="hl-1"> </span><span class="hl-3">--limit</span><span class="hl-1"> </span><span class="hl-7">500</span><span class="hl-1"> </span><span class="hl-3">--jsonl</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π-pnl-debug---pnldebug" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π PnL Debug (<code>--pnldebug</code>)<a href="#π-pnl-debug---pnldebug" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> can simulate a hypothetical position minute by minute and print running PnL, peak profit, and maximum drawdown for each candle β without placing any trades or loading a strategy file.</p> | |
| <a id="cli-flags-2" class="tsd-anchor"></a><h3 class="tsd-anchor-link">CLI Flags<a href="#cli-flags-2" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Flag</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>--pnldebug</code></td> | |
| <td>boolean</td> | |
| <td>Enable PnL debug mode</td> | |
| </tr> | |
| <tr> | |
| <td><code>--priceopen</code></td> | |
| <td>number</td> | |
| <td>Entry price (required)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--direction</code></td> | |
| <td>string</td> | |
| <td><code>long</code> or <code>short</code> (default: <code>long</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--when</code></td> | |
| <td>string</td> | |
| <td>Start timestamp β ISO 8601 or Unix ms (default: now)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--minutes</code></td> | |
| <td>string</td> | |
| <td>Number of 1m candles to simulate (default: <code>60</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--symbol</code></td> | |
| <td>string</td> | |
| <td>Trading pair (default: <code>"BTCUSDT"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--exchange</code></td> | |
| <td>string</td> | |
| <td>Exchange name (default: first registered, falls back to CCXT Binance)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--output</code></td> | |
| <td>string</td> | |
| <td>Output file base name (default: <code>{SYMBOL}_{DIRECTION}_{PRICEOPEN}_{TIMESTAMP}</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>--json</code></td> | |
| <td>boolean</td> | |
| <td>Save results as JSON array to <code>./dump/<output>.json</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>--jsonl</code></td> | |
| <td>boolean</td> | |
| <td>Save results as JSONL to <code>./dump/<output>.jsonl</code></td> | |
| </tr> | |
| <tr> | |
| <td><code>--markdown</code></td> | |
| <td>boolean</td> | |
| <td>Save results as Markdown table to <code>./dump/<output>.md</code></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="output-columns" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Output columns<a href="#output-columns" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Column</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>min</code></td> | |
| <td>Minute offset from start (1-based)</td> | |
| </tr> | |
| <tr> | |
| <td><code>timestamp</code></td> | |
| <td>Candle timestamp (ISO 8601)</td> | |
| </tr> | |
| <tr> | |
| <td><code>close</code></td> | |
| <td>Candle close price</td> | |
| </tr> | |
| <tr> | |
| <td><code>pnl%</code></td> | |
| <td>Running PnL vs entry price (signed %)</td> | |
| </tr> | |
| <tr> | |
| <td><code>peak%</code></td> | |
| <td>Highest PnL reached so far (always β₯ 0)</td> | |
| </tr> | |
| <tr> | |
| <td><code>drawdown%</code></td> | |
| <td>Lowest PnL reached so far (always β€ 0)</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="exchange-via-pnldebugmodule" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Exchange via <code>pnldebug.module</code><a href="#exchange-via-pnldebugmodule" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>By default the CLI registers CCXT Binance automatically. To use a different exchange, create a <code>modules/pnldebug.module.ts</code> file in the current working directory β the CLI loads it automatically before fetching candles.</p> | |
| <pre><code class="typescript"><span class="hl-6">// modules/pnldebug.module.ts</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">addExchangeSchema</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"backtest-kit"</span><span class="hl-1">;</span><br/><span class="hl-4">import</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1"> </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">"ccxt"</span><span class="hl-1">;</span><br/><br/><span class="hl-0">addExchangeSchema</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-5">exchangeName:</span><span class="hl-1"> </span><span class="hl-2">"my-exchange"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-0">getCandles</span><span class="hl-5">:</span><span class="hl-1"> </span><span class="hl-3">async</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">, </span><span class="hl-5">limit</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">exchange</span><span class="hl-1"> = </span><span class="hl-3">new</span><span class="hl-1"> </span><span class="hl-5">ccxt</span><span class="hl-1">.</span><span class="hl-0">bybit</span><span class="hl-1">({ </span><span class="hl-5">enableRateLimit:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-3">const</span><span class="hl-1"> </span><span class="hl-8">ohlcv</span><span class="hl-1"> = </span><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-5">exchange</span><span class="hl-1">.</span><span class="hl-0">fetchOHLCV</span><span class="hl-1">(</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">interval</span><span class="hl-1">, </span><span class="hl-5">since</span><span class="hl-1">.</span><span class="hl-0">getTime</span><span class="hl-1">(), </span><span class="hl-5">limit</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">return</span><span class="hl-1"> </span><span class="hl-5">ohlcv</span><span class="hl-1">.</span><span class="hl-0">map</span><span class="hl-1">(([</span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">]) </span><span class="hl-3">=></span><span class="hl-1"> ({</span><br/><span class="hl-1"> </span><span class="hl-5">timestamp</span><span class="hl-1">, </span><span class="hl-5">open</span><span class="hl-1">, </span><span class="hl-5">high</span><span class="hl-1">, </span><span class="hl-5">low</span><span class="hl-1">, </span><span class="hl-5">close</span><span class="hl-1">, </span><span class="hl-5">volume</span><span class="hl-1">,</span><br/><span class="hl-1"> }));</span><br/><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-0">formatPrice</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">price</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">price</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">2</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-0">formatQuantity</span><span class="hl-5">:</span><span class="hl-1"> (</span><span class="hl-5">symbol</span><span class="hl-1">, </span><span class="hl-5">quantity</span><span class="hl-1">) </span><span class="hl-3">=></span><span class="hl-1"> </span><span class="hl-5">quantity</span><span class="hl-1">.</span><span class="hl-0">toFixed</span><span class="hl-1">(</span><span class="hl-7">8</span><span class="hl-1">),</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="usage-1" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Usage<a href="#usage-1" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Print to stdout (default table format):</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--pnldebug</span><span class="hl-1"> </span><span class="hl-3">--symbol</span><span class="hl-1"> </span><span class="hl-2">BTCUSDT</span><span class="hl-1"> </span><span class="hl-3">--priceopen</span><span class="hl-1"> </span><span class="hl-7">64069.50</span><span class="hl-1"> </span><span class="hl-3">--direction</span><span class="hl-1"> </span><span class="hl-2">short</span><span class="hl-1"> </span><span class="hl-3">--when</span><span class="hl-1"> </span><span class="hl-2">"2025-02-25"</span><span class="hl-1"> </span><span class="hl-3">--minutes</span><span class="hl-1"> </span><span class="hl-7">120</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Save as Markdown:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--pnldebug</span><span class="hl-1"> </span><span class="hl-3">--priceopen</span><span class="hl-1"> </span><span class="hl-7">67956.73</span><span class="hl-1"> </span><span class="hl-3">--direction</span><span class="hl-1"> </span><span class="hl-2">long</span><span class="hl-1"> </span><span class="hl-3">--when</span><span class="hl-1"> </span><span class="hl-7">1772064000000</span><span class="hl-1"> </span><span class="hl-3">--minutes</span><span class="hl-1"> </span><span class="hl-7">60</span><span class="hl-1"> </span><span class="hl-3">--markdown</span><br/><span class="hl-6"># β ./dump/BTCUSDT_long_67956.73_{timestamp}.md</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Override the output file name with <code>--output</code>:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--pnldebug</span><span class="hl-1"> </span><span class="hl-3">--priceopen</span><span class="hl-1"> </span><span class="hl-7">64069.50</span><span class="hl-1"> </span><span class="hl-3">--direction</span><span class="hl-1"> </span><span class="hl-2">short</span><span class="hl-1"> </span><span class="hl-3">--when</span><span class="hl-1"> </span><span class="hl-2">"2025-02-25"</span><span class="hl-1"> </span><span class="hl-3">--minutes</span><span class="hl-1"> </span><span class="hl-7">120</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-3">--jsonl</span><span class="hl-1"> </span><span class="hl-3">--output</span><span class="hl-1"> </span><span class="hl-2">feb25_short_debug</span><br/><span class="hl-6"># β ./dump/feb25_short_debug.jsonl</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Or add it to <code>package.json</code>:</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"pnldebug"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --pnldebug --symbol BTCUSDT --priceopen 64069.50 --direction short --when </span><span class="hl-13">\"</span><span class="hl-2">2025-02-25</span><span class="hl-13">\"</span><span class="hl-2"> --minutes 120"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">pnldebug</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="example-stdout-output" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Example stdout output<a href="#example-stdout-output" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code><span class="hl-10">Symbol</span><span class="hl-1">: </span><span class="hl-8">BTCUSDT</span><span class="hl-1"> | </span><span class="hl-10">Direction</span><span class="hl-1">: </span><span class="hl-5">short</span><span class="hl-1"> | </span><span class="hl-10">PriceOpen</span><span class="hl-1">: </span><span class="hl-7">64069.50</span><span class="hl-1"> | </span><span class="hl-10">From</span><span class="hl-1">: </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">02</span><span class="hl-1">-25</span><span class="hl-10">T00</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><span class="hl-1"> | </span><span class="hl-10">Minutes</span><span class="hl-1">: </span><span class="hl-7">120</span><br/><br/><span class="hl-1"> </span><span class="hl-5">min</span><span class="hl-1"> | </span><span class="hl-5">timestamp</span><span class="hl-1"> | </span><span class="hl-5">close</span><span class="hl-1"> | </span><span class="hl-5">pnl</span><span class="hl-1">% | </span><span class="hl-5">peak</span><span class="hl-1">% | </span><span class="hl-5">drawdown</span><span class="hl-1">%</span><br/><span class="hl-1">-----------------------------------------------------------------------------------</span><br/><span class="hl-1"> </span><span class="hl-7">1</span><span class="hl-1"> | </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">02</span><span class="hl-1">-25</span><span class="hl-10">T00</span><span class="hl-1">:</span><span class="hl-7">01</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><span class="hl-1"> | </span><span class="hl-7">64020.10</span><span class="hl-1"> | +</span><span class="hl-7">0.08</span><span class="hl-1">% | +</span><span class="hl-7">0.08</span><span class="hl-1">% | </span><span class="hl-7">0.00</span><span class="hl-1">%</span><br/><span class="hl-1"> </span><span class="hl-7">2</span><span class="hl-1"> | </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">02</span><span class="hl-1">-25</span><span class="hl-10">T00</span><span class="hl-1">:</span><span class="hl-7">02</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><span class="hl-1"> | </span><span class="hl-7">64105.30</span><span class="hl-1"> | -</span><span class="hl-7">0.06</span><span class="hl-1">% | +</span><span class="hl-7">0.08</span><span class="hl-1">% | -</span><span class="hl-7">0.06</span><span class="hl-1">%</span><br/><span class="hl-1"> ...</span><br/><span class="hl-1"> </span><span class="hl-7">120</span><span class="hl-1"> | </span><span class="hl-7">2025</span><span class="hl-1">-</span><span class="hl-7">02</span><span class="hl-1">-25</span><span class="hl-10">T02</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">:</span><span class="hl-7">00</span><span class="hl-1">.000</span><span class="hl-8">Z</span><span class="hl-1"> | </span><span class="hl-7">63200.00</span><span class="hl-1"> | +</span><span class="hl-7">1.36</span><span class="hl-1">% | +</span><span class="hl-7">1.36</span><span class="hl-1">% | -</span><span class="hl-7">0.06</span><span class="hl-1">%</span> | |
| </code><button>Copy</button></pre> | |
| <a id="ποΈ-flushing-strategy-output---flush" class="tsd-anchor"></a><h2 class="tsd-anchor-link">ποΈ Flushing Strategy Output (<code>--flush</code>)<a href="#ποΈ-flushing-strategy-output---flush" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> can delete generated output folders from one or more strategy dump directories without touching cached candle data.</p> | |
| <a id="cli-flags-3" class="tsd-anchor"></a><h3 class="tsd-anchor-link">CLI Flags<a href="#cli-flags-3" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Flag</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>--flush</code></td> | |
| <td>boolean</td> | |
| <td>Enable flush mode</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p><strong>Positional arguments (required):</strong> one or more strategy entry point files. For each entry point the CLI resolves its directory and removes the following subdirectories from <code><entry-dir>/dump/</code>:</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Folder</th> | |
| <th>Contents</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>report</code></td> | |
| <td>Backtest report files (<code>.jsonl</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>log</code></td> | |
| <td>Run logs (<code>log.jsonl</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>markdown</code></td> | |
| <td>Exported Markdown reports</td> | |
| </tr> | |
| <tr> | |
| <td><code>agent</code></td> | |
| <td>Agent outline files</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p>Candle cache (<code>dump/data/</code>) and AI forecast outlines (<code>dump/outline/</code>) are <strong>not</strong> removed.</p> | |
| <a id="usage-2" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Usage<a href="#usage-2" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Flush a single strategy:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--flush</span><span class="hl-1"> </span><span class="hl-2">./content/feb_2026.strategy/modules/backtest.module.ts</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Flush multiple strategies at once:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--flush</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-2">./content/feb_2026.strategy/modules/backtest.module.ts</span><span class="hl-1"> </span><span class="hl-13">\</span><br/><span class="hl-1"> </span><span class="hl-2">./content/mar_2026.strategy/modules/backtest.module.ts</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Or add it to <code>package.json</code>:</p> | |
| <pre><code class="json"><span class="hl-1">{</span><br/><span class="hl-1"> </span><span class="hl-16">"scripts"</span><span class="hl-1">: {</span><br/><span class="hl-1"> </span><span class="hl-16">"flush"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --flush ./content/feb_2026.strategy/modules/backtest.module.ts"</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">}</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">flush</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="ποΈ-scaffolding-a-new-project---init" class="tsd-anchor"></a><h2 class="tsd-anchor-link">ποΈ Scaffolding a New Project (<code>--init</code>)<a href="#ποΈ-scaffolding-a-new-project---init" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p><code>@backtest-kit/cli</code> can bootstrap a ready-to-use project directory with a pre-configured layout, example strategy files, and all documentation fetched automatically.</p> | |
| <a id="cli-flags-4" class="tsd-anchor"></a><h3 class="tsd-anchor-link">CLI Flags<a href="#cli-flags-4" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><table> | |
| <thead> | |
| <tr> | |
| <th>Flag</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>--init</code></td> | |
| <td>boolean</td> | |
| <td>Scaffold a new project</td> | |
| </tr> | |
| <tr> | |
| <td><code>--output</code></td> | |
| <td>string</td> | |
| <td>Target directory name (default: <code>backtest-kit-project</code>)</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="usage-3" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Usage<a href="#usage-3" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--init</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Creates <code>./backtest-kit-project/</code> in the current working directory.</p> | |
| <p>Override the directory name with <code>--output</code>:</p> | |
| <pre><code class="bash"><span class="hl-0">npx</span><span class="hl-1"> </span><span class="hl-2">@backtest-kit/cli</span><span class="hl-1"> </span><span class="hl-3">--init</span><span class="hl-1"> </span><span class="hl-3">--output</span><span class="hl-1"> </span><span class="hl-2">my-trading-bot</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Creates <code>./my-trading-bot/</code>.</p> | |
| <p>The target directory must not exist or must be empty β the command aborts if it contains any files.</p> | |
| <a id="generated-project-structure" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Generated Project Structure<a href="#generated-project-structure" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code><span class="hl-5">backtest</span><span class="hl-1">-</span><span class="hl-5">kit</span><span class="hl-1">-</span><span class="hl-5">project</span><span class="hl-1">/</span><br/><span class="hl-1">βββ </span><span class="hl-5">package</span><span class="hl-1">.</span><span class="hl-5">json</span><span class="hl-1"> # </span><span class="hl-5">pre</span><span class="hl-1">-</span><span class="hl-5">configured</span><span class="hl-1"> </span><span class="hl-4">with</span><span class="hl-1"> </span><span class="hl-5">all</span><span class="hl-1"> </span><span class="hl-5">backtest</span><span class="hl-1">-</span><span class="hl-5">kit</span><span class="hl-1"> </span><span class="hl-5">dependencies</span><br/><span class="hl-1">βββ .</span><span class="hl-5">gitignore</span><br/><span class="hl-1">βββ </span><span class="hl-8">CLAUDE</span><span class="hl-1">.</span><span class="hl-5">md</span><span class="hl-1"> # </span><span class="hl-8">AI</span><span class="hl-1">-</span><span class="hl-5">agent</span><span class="hl-1"> </span><span class="hl-5">guide</span><span class="hl-1"> </span><span class="hl-5">for</span><span class="hl-1"> </span><span class="hl-5">writing</span><span class="hl-1"> </span><span class="hl-5">strategies</span><br/><span class="hl-1">βββ </span><span class="hl-5">content</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">feb_2026</span><span class="hl-1">.</span><span class="hl-5">strategy</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> # </span><span class="hl-5">example</span><span class="hl-1"> </span><span class="hl-5">strategy</span><span class="hl-1"> </span><span class="hl-5">entry</span><span class="hl-1"> </span><span class="hl-5">point</span><br/><span class="hl-1">βββ </span><span class="hl-5">docs</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">lib</span><span class="hl-1">/ # </span><span class="hl-5">fetched</span><span class="hl-1"> </span><span class="hl-0">automatically</span><span class="hl-1"> (</span><span class="hl-5">see</span><span class="hl-1"> </span><span class="hl-5">below</span><span class="hl-1">)</span><br/><span class="hl-1">β βββ </span><span class="hl-5">backtest_actions</span><span class="hl-1">.</span><span class="hl-5">md</span><br/><span class="hl-1">β βββ </span><span class="hl-5">backtest_graph_pattern</span><span class="hl-1">.</span><span class="hl-5">md</span><br/><span class="hl-1">β βββ </span><span class="hl-5">backtest_logging_jsonl</span><span class="hl-1">.</span><span class="hl-5">md</span><br/><span class="hl-1">β βββ </span><span class="hl-5">backtest_pinets_usage</span><span class="hl-1">.</span><span class="hl-5">md</span><br/><span class="hl-1">β βββ </span><span class="hl-5">backtest_risk_async</span><span class="hl-1">.</span><span class="hl-5">md</span><br/><span class="hl-1">β βββ </span><span class="hl-5">backtest_strategy_structure</span><span class="hl-1">.</span><span class="hl-5">md</span><br/><span class="hl-1">β βββ </span><span class="hl-5">pine_debug</span><span class="hl-1">.</span><span class="hl-5">md</span><br/><span class="hl-1">β βββ </span><span class="hl-5">pine_indicator_warmup</span><span class="hl-1">.</span><span class="hl-5">md</span><br/><span class="hl-1">βββ </span><span class="hl-5">math</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">feb_2026</span><span class="hl-1">.</span><span class="hl-5">pine</span><span class="hl-1"> # </span><span class="hl-5">example</span><span class="hl-1"> </span><span class="hl-5">PineScript</span><span class="hl-1"> </span><span class="hl-5">indicator</span><br/><span class="hl-1">βββ </span><span class="hl-5">modules</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">dump</span><span class="hl-1">.</span><span class="hl-5">module</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> # </span><span class="hl-5">exchange</span><span class="hl-1"> </span><span class="hl-5">schema</span><span class="hl-1"> </span><span class="hl-5">for</span><span class="hl-1"> --</span><span class="hl-5">dump</span><span class="hl-1"> </span><span class="hl-5">mode</span><br/><span class="hl-1">β βββ </span><span class="hl-5">pine</span><span class="hl-1">.</span><span class="hl-5">module</span><span class="hl-1">.</span><span class="hl-5">ts</span><span class="hl-1"> # </span><span class="hl-5">exchange</span><span class="hl-1"> </span><span class="hl-5">schema</span><span class="hl-1"> </span><span class="hl-5">for</span><span class="hl-1"> --</span><span class="hl-5">pine</span><span class="hl-1"> </span><span class="hl-5">mode</span><br/><span class="hl-1">βββ </span><span class="hl-5">report</span><span class="hl-1">/</span><br/><span class="hl-1">β βββ </span><span class="hl-5">feb_2026</span><span class="hl-1">.</span><span class="hl-5">md</span><span class="hl-1"> # </span><span class="hl-5">example</span><span class="hl-1"> </span><span class="hl-5">strategy</span><span class="hl-1"> </span><span class="hl-5">research</span><span class="hl-1"> </span><span class="hl-5">report</span><br/><span class="hl-1">βββ </span><span class="hl-5">scripts</span><span class="hl-1">/</span><br/><span class="hl-1"> βββ </span><span class="hl-5">fetch_docs</span><span class="hl-1">.</span><span class="hl-5">mjs</span><span class="hl-1"> # </span><span class="hl-10">utility</span><span class="hl-1">: </span><span class="hl-5">downloads</span><span class="hl-1"> </span><span class="hl-5">library</span><span class="hl-1"> </span><span class="hl-5">READMEs</span><span class="hl-1"> </span><span class="hl-5">into</span><span class="hl-1"> </span><span class="hl-5">docs</span><span class="hl-1">/</span><span class="hl-5">lib</span><span class="hl-1">/</span> | |
| </code><button>Copy</button></pre> | |
| <a id="automatic-documentation-fetch" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Automatic Documentation Fetch<a href="#automatic-documentation-fetch" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>After scaffolding, the CLI immediately runs <code>scripts/fetch_docs.mjs</code> inside the new project, which downloads the latest README files for all bundled libraries into <code>docs/lib/</code>:</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>File</th> | |
| <th>Source</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>backtest-kit.md</code></td> | |
| <td><code>backtest-kit</code> README</td> | |
| </tr> | |
| <tr> | |
| <td><code>backtest-kit__graph.md</code></td> | |
| <td><code>@backtest-kit/graph</code> README</td> | |
| </tr> | |
| <tr> | |
| <td><code>backtest-kit__pinets.md</code></td> | |
| <td><code>@backtest-kit/pinets</code> README</td> | |
| </tr> | |
| <tr> | |
| <td><code>backtest-kit__cli.md</code></td> | |
| <td><code>@backtest-kit/cli</code> README</td> | |
| </tr> | |
| <tr> | |
| <td><code>garch.md</code></td> | |
| <td><code>garch</code> README</td> | |
| </tr> | |
| <tr> | |
| <td><code>volume-anomaly.md</code></td> | |
| <td><code>volume-anomaly</code> README</td> | |
| </tr> | |
| <tr> | |
| <td><code>agent-swarm-kit.md</code></td> | |
| <td><code>agent-swarm-kit</code> README</td> | |
| </tr> | |
| <tr> | |
| <td><code>functools-kit.md</code></td> | |
| <td><code>functools-kit</code> README</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p>You can re-run this script at any time to refresh the docs:</p> | |
| <pre><code class="bash"><span class="hl-0">cd</span><span class="hl-1"> </span><span class="hl-2">backtest-kit-project</span><br/><span class="hl-0">node</span><span class="hl-1"> </span><span class="hl-2">./scripts/fetch_docs.mjs</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p>Or via the pre-configured npm script:</p> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">sync:lib</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π-environment-variables" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π Environment Variables<a href="#π-environment-variables" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Create a <code>.env</code> file in your project root:</p> | |
| <pre><code class="env"># Telegram notifications (required for --telegram) | |
| CC_TELEGRAM_TOKEN=your_bot_token_here | |
| CC_TELEGRAM_CHANNEL=-100123456789 | |
| # Web UI server (optional, defaults shown) | |
| CC_WWWROOT_HOST=0.0.0.0 | |
| CC_WWWROOT_PORT=60050 | |
| # Custom QuickChart service URL (optional) | |
| CC_QUICKCHART_HOST= | |
| </code><button type="button">Copy</button></pre> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Variable</th> | |
| <th>Default</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>CC_TELEGRAM_TOKEN</code></td> | |
| <td>β</td> | |
| <td>Telegram bot token (from @BotFather)</td> | |
| </tr> | |
| <tr> | |
| <td><code>CC_TELEGRAM_CHANNEL</code></td> | |
| <td>β</td> | |
| <td>Telegram channel or chat ID</td> | |
| </tr> | |
| <tr> | |
| <td><code>CC_WWWROOT_HOST</code></td> | |
| <td><code>0.0.0.0</code></td> | |
| <td>UI server bind address</td> | |
| </tr> | |
| <tr> | |
| <td><code>CC_WWWROOT_PORT</code></td> | |
| <td><code>60050</code></td> | |
| <td>UI server port</td> | |
| </tr> | |
| <tr> | |
| <td><code>CC_QUICKCHART_HOST</code></td> | |
| <td>β</td> | |
| <td>Self-hosted QuickChart instance URL</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="βοΈ-default-behaviors" class="tsd-anchor"></a><h2 class="tsd-anchor-link">βοΈ Default Behaviors<a href="#βοΈ-default-behaviors" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>When your strategy module does not register an exchange, frame, or strategy name, the CLI falls back to built-in defaults and prints a console warning:</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Component</th> | |
| <th>Default</th> | |
| <th>Warning</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><strong>Exchange</strong></td> | |
| <td>CCXT Binance (<code>default_exchange</code>)</td> | |
| <td><code>Warning: The default exchange schema is set to CCXT Binance...</code></td> | |
| </tr> | |
| <tr> | |
| <td><strong>Frame</strong></td> | |
| <td>February 2024 (<code>default_frame</code>)</td> | |
| <td><code>Warning: The default frame schema is set to February 2024...</code></td> | |
| </tr> | |
| <tr> | |
| <td><strong>Symbol</strong></td> | |
| <td><code>BTCUSDT</code></td> | |
| <td>β</td> | |
| </tr> | |
| <tr> | |
| <td><strong>Cache intervals</strong></td> | |
| <td><code>1m, 15m, 30m, 4h</code></td> | |
| <td>Used if <code>--cacheInterval</code> not provided; skip entirely with <code>--noCache</code></td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <blockquote> | |
| <p><strong>Note:</strong> The default exchange schema <strong>does not support order book fetching in backtest mode</strong>. If your strategy calls <code>getOrderBook()</code> during backtest, you must register a custom exchange schema with your own snapshot storage.</p> | |
| </blockquote> | |
| <a id="π§-programmatic-api" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π§ Programmatic API<a href="#π§-programmatic-api" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>In addition to the CLI, <code>@backtest-kit/cli</code> can be used as a library β call <code>run()</code> directly from your own script without spawning a child process or parsing CLI flags.</p> | |
| <a id="runmode-args" class="tsd-anchor"></a><h3 class="tsd-anchor-link"><code>run(mode, args)</code><a href="#runmode-args" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><pre><code class="typescript"><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">run</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'@backtest-kit/cli'</span><span class="hl-1">;</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-0">run</span><span class="hl-1">(</span><span class="hl-5">mode</span><span class="hl-1">, </span><span class="hl-5">args</span><span class="hl-1">);</span> | |
| </code><button type="button">Copy</button></pre> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Parameter</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>mode</code></td> | |
| <td><code>"backtest" | "paper" | "live"</code> β Execution mode</td> | |
| </tr> | |
| <tr> | |
| <td><code>args</code></td> | |
| <td>Mode-specific options (all optional β same defaults as CLI)</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p><code>run()</code> can be called <strong>only once per process</strong>. A second call throws <code>"Should be called only once"</code>.</p> | |
| <a id="payload-fields" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Payload fields<a href="#payload-fields" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p><strong>Backtest</strong> (<code>mode: "backtest"</code>):</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Field</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>entryPoint</code></td> | |
| <td><code>string</code></td> | |
| <td>Path to strategy entry point file</td> | |
| </tr> | |
| <tr> | |
| <td><code>symbol</code></td> | |
| <td><code>string</code></td> | |
| <td>Trading pair (default: <code>"BTCUSDT"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>strategy</code></td> | |
| <td><code>string</code></td> | |
| <td>Strategy name (default: first registered)</td> | |
| </tr> | |
| <tr> | |
| <td><code>exchange</code></td> | |
| <td><code>string</code></td> | |
| <td>Exchange name (default: first registered)</td> | |
| </tr> | |
| <tr> | |
| <td><code>frame</code></td> | |
| <td><code>string</code></td> | |
| <td>Frame name (default: first registered)</td> | |
| </tr> | |
| <tr> | |
| <td><code>cacheInterval</code></td> | |
| <td><code>CandleInterval[]</code></td> | |
| <td>Intervals to pre-cache (default: <code>["1m","15m","30m","1h","4h"]</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>noCache</code></td> | |
| <td><code>boolean</code></td> | |
| <td>Skip candle cache warming (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>noFlush</code></td> | |
| <td><code>boolean</code></td> | |
| <td>Skip removing report/log/markdown/agent folders before the run (default: <code>false</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>verbose</code></td> | |
| <td><code>boolean</code></td> | |
| <td>Log each candle fetch (default: <code>false</code>)</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <p><strong>Paper</strong> and <strong>Live</strong> (<code>mode: "paper"</code> / <code>mode: "live"</code>):</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Field</th> | |
| <th>Type</th> | |
| <th>Description</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><code>entryPoint</code></td> | |
| <td><code>string</code></td> | |
| <td>Path to strategy entry point file</td> | |
| </tr> | |
| <tr> | |
| <td><code>symbol</code></td> | |
| <td><code>string</code></td> | |
| <td>Trading pair (default: <code>"BTCUSDT"</code>)</td> | |
| </tr> | |
| <tr> | |
| <td><code>strategy</code></td> | |
| <td><code>string</code></td> | |
| <td>Strategy name (default: first registered)</td> | |
| </tr> | |
| <tr> | |
| <td><code>exchange</code></td> | |
| <td><code>string</code></td> | |
| <td>Exchange name (default: first registered)</td> | |
| </tr> | |
| <tr> | |
| <td><code>verbose</code></td> | |
| <td><code>boolean</code></td> | |
| <td>Log each candle fetch (default: <code>false</code>)</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <a id="examples" class="tsd-anchor"></a><h3 class="tsd-anchor-link">Examples<a href="#examples" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p><strong>Backtest:</strong></p> | |
| <pre><code class="typescript"><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">run</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'@backtest-kit/cli'</span><span class="hl-1">;</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-0">run</span><span class="hl-1">(</span><span class="hl-2">'backtest'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">entryPoint:</span><span class="hl-1"> </span><span class="hl-2">'./src/index.mjs'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">symbol:</span><span class="hl-1"> </span><span class="hl-2">'ETHUSDT'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">frame:</span><span class="hl-1"> </span><span class="hl-2">'feb-2024'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">cacheInterval:</span><span class="hl-1"> [</span><span class="hl-2">'1m'</span><span class="hl-1">, </span><span class="hl-2">'15m'</span><span class="hl-1">, </span><span class="hl-2">'1h'</span><span class="hl-1">],</span><br/><span class="hl-1"> </span><span class="hl-5">verbose:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p><strong>Paper trading:</strong></p> | |
| <pre><code class="typescript"><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">run</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'@backtest-kit/cli'</span><span class="hl-1">;</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-0">run</span><span class="hl-1">(</span><span class="hl-2">'paper'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">entryPoint:</span><span class="hl-1"> </span><span class="hl-2">'./src/index.mjs'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">symbol:</span><span class="hl-1"> </span><span class="hl-2">'BTCUSDT'</span><span class="hl-1">,</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p><strong>Live trading:</strong></p> | |
| <pre><code class="typescript"><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">run</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'@backtest-kit/cli'</span><span class="hl-1">;</span><br/><br/><span class="hl-4">await</span><span class="hl-1"> </span><span class="hl-0">run</span><span class="hl-1">(</span><span class="hl-2">'live'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-5">entryPoint:</span><span class="hl-1"> </span><span class="hl-2">'./src/index.mjs'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">symbol:</span><span class="hl-1"> </span><span class="hl-2">'BTCUSDT'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">verbose:</span><span class="hl-1"> </span><span class="hl-3">true</span><span class="hl-1">,</span><br/><span class="hl-1">});</span> | |
| </code><button type="button">Copy</button></pre> | |
| <a id="π‘-why-use-backtest-kitcli" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π‘ Why Use @backtest-kit/cli?<a href="#π‘-why-use-backtest-kitcli" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Instead of writing infrastructure code for every project:</p> | |
| <p><strong>β Without @backtest-kit/cli (manual setup)</strong></p> | |
| <pre><code class="typescript"><span class="hl-6">// index.ts</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">setLogger</span><span class="hl-1">, </span><span class="hl-5">setConfig</span><span class="hl-1">, </span><span class="hl-5">Storage</span><span class="hl-1">, </span><span class="hl-5">Notification</span><span class="hl-1">, </span><span class="hl-5">Report</span><span class="hl-1">, </span><span class="hl-5">Markdown</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'backtest-kit'</span><span class="hl-1">;</span><br/><span class="hl-4">import</span><span class="hl-1"> { </span><span class="hl-5">serve</span><span class="hl-1"> } </span><span class="hl-4">from</span><span class="hl-1"> </span><span class="hl-2">'@backtest-kit/ui'</span><span class="hl-1">;</span><br/><br/><span class="hl-0">setLogger</span><span class="hl-1">({ </span><span class="hl-5">log:</span><span class="hl-1"> </span><span class="hl-5">console</span><span class="hl-1">.</span><span class="hl-5">log</span><span class="hl-1">, ... });</span><br/><span class="hl-5">Storage</span><span class="hl-1">.</span><span class="hl-0">enable</span><span class="hl-1">();</span><br/><span class="hl-5">Notification</span><span class="hl-1">.</span><span class="hl-0">enable</span><span class="hl-1">();</span><br/><span class="hl-5">Report</span><span class="hl-1">.</span><span class="hl-0">enable</span><span class="hl-1">();</span><br/><span class="hl-5">Markdown</span><span class="hl-1">.</span><span class="hl-0">disable</span><span class="hl-1">();</span><br/><br/><span class="hl-6">// ... parse CLI args manually</span><br/><span class="hl-6">// ... register exchange schema</span><br/><span class="hl-6">// ... warm candle cache</span><br/><span class="hl-6">// ... set up Telegram bot</span><br/><span class="hl-6">// ... handle SIGINT gracefully</span><br/><span class="hl-6">// ... load and run backtest</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p><strong>β With @backtest-kit/cli (one script)</strong></p> | |
| <pre><code class="json"><span class="hl-1">{ </span><span class="hl-16">"scripts"</span><span class="hl-1">: { </span><span class="hl-16">"backtest"</span><span class="hl-1">: </span><span class="hl-2">"npx @backtest-kit/cli --backtest --ui --telegram ./src/index.mjs"</span><span class="hl-1"> } }</span> | |
| </code><button type="button">Copy</button></pre> | |
| <pre><code class="bash"><span class="hl-0">npm</span><span class="hl-1"> </span><span class="hl-2">run</span><span class="hl-1"> </span><span class="hl-2">backtest</span> | |
| </code><button type="button">Copy</button></pre> | |
| <p><strong>Benefits:</strong></p> | |
| <ul> | |
| <li>π From zero to running backtest in seconds</li> | |
| <li>πΎ Automatic candle cache warming with retry logic</li> | |
| <li>π Production-ready web dashboard out of the box</li> | |
| <li>π¬ Telegram notifications with price charts β no chart code needed</li> | |
| <li>π Graceful shutdown on SIGINT β no hanging processes</li> | |
| <li>π Works with any <code>backtest-kit</code> strategy file as-is</li> | |
| <li>π§© Broker adapter hooks via side-effect module files β no CLI internals to touch</li> | |
| </ul> | |
| <a id="π€-contribute" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π€ Contribute<a href="#π€-contribute" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Fork/PR on <a href="https://github.com/tripolskypetr/backtest-kit">GitHub</a>.</p> | |
| <a id="π-license" class="tsd-anchor"></a><h2 class="tsd-anchor-link">π License<a href="#π-license" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>MIT Β© <a href="https://github.com/tripolskypetr">tripolskypetr</a></p> | |
| </div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><h3><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#π-backtest-kitcli"><span>π @backtest-<wbr/>kit/cli</span></a><ul><li><a href="#β¨-features"><span>β¨ <wbr/>Features</span></a></li><li><a href="#π-what-it-does"><span>π <wbr/>What <wbr/>It <wbr/>Does</span></a></li><li><a href="#π-installation"><span>π <wbr/>Installation</span></a></li><li><a href="#π-quick-start"><span>π <wbr/>Quick <wbr/>Start</span></a></li><li><a href="#ποΈ-cli-flags"><span>ποΈ CLI <wbr/>Flags</span></a></li><li><a href="#π-execution-modes"><span>π <wbr/>Execution <wbr/>Modes</span></a></li><li><ul><li><a href="#backtest"><span>Backtest</span></a></li><li><a href="#paper-trading"><span>Paper <wbr/>Trading</span></a></li><li><a href="#live-trading"><span>Live <wbr/>Trading</span></a></li><li><a href="#walker--ab-strategy-comparison"><span>Walker β <wbr/>A/<wbr/>B <wbr/>Strategy <wbr/>Comparison</span></a></li></ul></li><li><a href="#ποΈ-monorepo-usage"><span>ποΈ <wbr/>Monorepo <wbr/>Usage</span></a></li><li><ul><li><a href="#how-it-works"><span>How <wbr/>It <wbr/>Works</span></a></li><li><a href="#project-structure"><span>Project <wbr/>Structure</span></a></li><li><a href="#root-packagejson"><span>Root package.json</span></a></li><li><a href="#isolated-resources-per-strategy"><span>Isolated <wbr/>Resources <wbr/>Per <wbr/>Strategy</span></a></li></ul></li><li><a href="#π-shared-import-aliases"><span>π <wbr/>Shared <wbr/>Import <wbr/>Aliases</span></a></li><li><ul><li><a href="#how-it-works-1"><span>How <wbr/>It <wbr/>Works</span></a></li><li><a href="#project-structure-1"><span>Project <wbr/>Structure</span></a></li><li><a href="#typescript-support"><span>Type<wbr/>Script <wbr/>Support</span></a></li></ul></li><li><a href="#π-integrations"><span>π <wbr/>Integrations</span></a></li><li><ul><li><a href="#web-dashboard---ui"><span>Web <wbr/>Dashboard (--ui)</span></a></li><li><ul><li><a href="#symbol-list-symbolconfig"><span>Symbol <wbr/>List (symbol.config)</span></a></li><li><a href="#notification-filter-notificationconfig"><span>Notification <wbr/>Filter (notification.config)</span></a></li></ul></li><li><a href="#telegram-notifications---telegram"><span>Telegram <wbr/>Notifications (--telegram)</span></a></li><li><ul><li><a href="#telegram-message-adapter-telegramconfig"><span>Telegram <wbr/>Message <wbr/>Adapter (telegram.config)</span></a></li></ul></li></ul></li><li><a href="#π§©-module-hooks-broker-adapter"><span>π§© <wbr/>Module <wbr/>Hooks (<wbr/>Broker <wbr/>Adapter)</span></a></li><li><ul><li><a href="#how-it-works-2"><span>How <wbr/>It <wbr/>Works</span></a></li><li><a href="#available-broker-hooks"><span>Available <wbr/>Broker <wbr/>Hooks</span></a></li><li><a href="#typescript"><span>Type<wbr/>Script</span></a></li></ul></li><li><a href="#π-import-aliases-aliasmodule"><span>π <wbr/>Import <wbr/>Aliases (alias.module)</span></a></li><li><a href="#π¦-supported-entry-point-formats"><span>π¦ <wbr/>Supported <wbr/>Entry <wbr/>Point <wbr/>Formats</span></a></li><li><ul><li><a href="#typescript-ts"><span>Type<wbr/>Script (.ts)</span></a></li><li><a href="#es-module-mjs"><span>ES <wbr/>Module (.mjs)</span></a></li><li><a href="#commonjs-cjs"><span>CommonJS (.cjs)</span></a></li></ul></li><li><a href="#π²-running-local-pinescript-indicators"><span>π² <wbr/>Running <wbr/>Local <wbr/>Pine<wbr/>Script <wbr/>Indicators</span></a></li><li><ul><li><a href="#cli-flags"><span>CLI <wbr/>Flags</span></a></li><li><a href="#exchange-via-pinemodule"><span>Exchange via pine.module</span></a></li><li><a href="#environment-variables-env"><span>Environment variables (.env)</span></a></li><li><a href="#pinescript-requirements"><span>Pine<wbr/>Script <wbr/>Requirements</span></a></li><li><a href="#output"><span>Output</span></a></li></ul></li><li><a href="#π¨-visual-pine-script-editor"><span>π¨ <wbr/>Visual <wbr/>Pine <wbr/>Script <wbr/>Editor</span></a></li><li><ul><li><a href="#usage"><span>Usage</span></a></li><li><a href="#exchange-via-editormodule"><span>Exchange via editor.module</span></a></li><li><a href="#environment-variables"><span>Environment <wbr/>Variables</span></a></li><li><a href="#packagejson-script"><span>package.json script</span></a></li></ul></li><li><a href="#πΎ-dumping-raw-candles"><span>πΎ <wbr/>Dumping <wbr/>Raw <wbr/>Candles</span></a></li><li><ul><li><a href="#cli-flags-1"><span>CLI <wbr/>Flags</span></a></li><li><a href="#exchange-via-dumpmodule"><span>Exchange via dump.module</span></a></li><li><a href="#output-1"><span>Output</span></a></li></ul></li><li><a href="#π-pnl-debug---pnldebug"><span>π <wbr/>Pn<wbr/>L <wbr/>Debug (--pnldebug)</span></a></li><li><ul><li><a href="#cli-flags-2"><span>CLI <wbr/>Flags</span></a></li><li><a href="#output-columns"><span>Output columns</span></a></li><li><a href="#exchange-via-pnldebugmodule"><span>Exchange via pnldebug.module</span></a></li><li><a href="#usage-1"><span>Usage</span></a></li><li><a href="#example-stdout-output"><span>Example stdout output</span></a></li></ul></li><li><a href="#ποΈ-flushing-strategy-output---flush"><span>ποΈ <wbr/>Flushing <wbr/>Strategy <wbr/>Output (--flush)</span></a></li><li><ul><li><a href="#cli-flags-3"><span>CLI <wbr/>Flags</span></a></li><li><a href="#usage-2"><span>Usage</span></a></li></ul></li><li><a href="#ποΈ-scaffolding-a-new-project---init"><span>ποΈ <wbr/>Scaffolding a <wbr/>New <wbr/>Project (--init)</span></a></li><li><ul><li><a href="#cli-flags-4"><span>CLI <wbr/>Flags</span></a></li><li><a href="#usage-3"><span>Usage</span></a></li><li><a href="#generated-project-structure"><span>Generated <wbr/>Project <wbr/>Structure</span></a></li><li><a href="#automatic-documentation-fetch"><span>Automatic <wbr/>Documentation <wbr/>Fetch</span></a></li></ul></li><li><a href="#π-environment-variables"><span>π <wbr/>Environment <wbr/>Variables</span></a></li><li><a href="#βοΈ-default-behaviors"><span>βοΈ <wbr/>Default <wbr/>Behaviors</span></a></li><li><a href="#π§-programmatic-api"><span>π§ <wbr/>Programmatic API</span></a></li><li><ul><li><a href="#runmode-args"><span>run(mode, args)</span></a></li><li><a href="#payload-fields"><span>Payload fields</span></a></li><li><a href="#examples"><span>Examples</span></a></li></ul></li><li><a href="#π‘-why-use-backtest-kitcli"><span>π‘ <wbr/>Why <wbr/>Use @backtest-<wbr/>kit/cli?</span></a></li><li><a href="#π€-contribute"><span>π€ <wbr/>Contribute</span></a></li><li><a href="#π-license"><span>π <wbr/>License</span></a></li></ul></div></details></div><div class="site-menu"><nav class="tsd-navigation"><a href="../modules.html">backtest-kit</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer><p class="tsd-generator">Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p></footer><div class="overlay"></div></body></html> | |
| <!-- Yandex.Metrika counter --> | |
| <script type="text/javascript"> | |
| (function(m,e,t,r,i,k,a){ | |
| m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)}; | |
| m[i].l=1*new Date(); | |
| for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }} | |
| k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a) | |
| })(window, document,'script','https://mc.yandex.ru/metrika/tag.js?id=105455585', 'ym'); | |
| ym(105455585, 'init', {ssr:true, webvisor:true, clickmap:true, ecommerce:"dataLayer", accurateTrackBounce:true, trackLinks:true}); | |
| </script> | |
| <noscript><div><img src="https://mc.yandex.ru/watch/105455585" style="position:absolute; left:-9999px;" alt="" /></div></noscript> | |
| <!-- /Yandex.Metrika counter --> | |
| <!-- Google tag (gtag.js) --> | |
| <script async src="https://www.googletagmanager.com/gtag/js?id=G-3MQZEBBDDR"></script> | |
| <script> | |
| window.dataLayer = window.dataLayer || []; | |
| function gtag(){dataLayer.push(arguments);} | |
| gtag('js', new Date()); | |
| gtag('config', 'G-3MQZEBBDDR'); | |
| </script> | |