backtest-kit 1.10.1 โ 1.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +259 -259
- package/build/index.cjs +465 -31
- package/build/index.mjs +465 -31
- package/package.json +81 -81
- package/types.d.ts +197 -19
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 Petr Tripolsky
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Petr Tripolsky
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,259 +1,259 @@
|
|
|
1
|
-
<img src="./assets/triangle.svg" height="105px" align="right">
|
|
2
|
-
|
|
3
|
-
# ๐งฟ Backtest Kit
|
|
4
|
-
|
|
5
|
-
> A TypeScript framework for backtesting and live trading strategies on multi-asset, crypto, forex or [DEX (peer-to-peer marketplace)](https://en.wikipedia.org/wiki/Decentralized_finance#Decentralized_exchanges) with crash-safe persistence, signal validation, and AI optimization.
|
|
6
|
-
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
[](https://deepwiki.com/tripolskypetr/backtest-kit)
|
|
10
|
-
[](https://npmjs.org/package/backtest-kit)
|
|
11
|
-
[]()
|
|
12
|
-
|
|
13
|
-
Build reliable trading systems: backtest on historical data, deploy live bots with recovery, and optimize strategies using LLMs like Ollama.
|
|
14
|
-
|
|
15
|
-
๐ **[API Reference](https://backtest-kit.github.io/documents/example_02_first_backtest.html)** | ๐ **[Quick Start](https://github.com/tripolskypetr/backtest-kit/tree/master/demo)** | **๐ฐ [Article](https://backtest-kit.github.io/documents/article_02_second_order_chaos.html)**
|
|
16
|
-
|
|
17
|
-
## โจ Why Choose Backtest Kit?
|
|
18
|
-
|
|
19
|
-
- ๐ **Production-Ready**: Seamless switch between backtest/live modes; identical code across environments.
|
|
20
|
-
- ๐พ **Crash-Safe**: Atomic persistence recovers states after crashes, preventing duplicates or losses.
|
|
21
|
-
- โ
**Validation**: Checks signals for TP/SL logic, risk/reward ratios, and portfolio limits.
|
|
22
|
-
- ๐ **Efficient Execution**: Streaming architecture for large datasets; VWAP pricing for realism.
|
|
23
|
-
- ๐ค **AI Integration**: LLM-powered strategy generation (Optimizer) with multi-timeframe analysis.
|
|
24
|
-
- ๐ **Reports & Metrics**: Auto Markdown reports with PNL, Sharpe Ratio, win rate, and more.
|
|
25
|
-
- ๐ก๏ธ **Risk Management**: Custom rules for position limits, time windows, and multi-strategy coordination.
|
|
26
|
-
- ๐ **Pluggable**: Custom data sources (CCXT), persistence (file/Redis), and sizing calculators.
|
|
27
|
-
- ๐งช **Tested**: 300+ unit/integration tests for validation, recovery, and events.
|
|
28
|
-
- ๐ **Self hosted**: Zero dependency on third-party node_modules or platforms; run entirely in your own environment.
|
|
29
|
-
|
|
30
|
-
## ๐ Supported Order Types
|
|
31
|
-
|
|
32
|
-
- Market/Limit entries
|
|
33
|
-
- TP/SL/OCO exits
|
|
34
|
-
- Grid with auto-cancel on unmet conditions
|
|
35
|
-
- Partial profit/loss levels
|
|
36
|
-
- Trailing stop-loss
|
|
37
|
-
- Breakeven protection
|
|
38
|
-
|
|
39
|
-
## ๐ Quick Start
|
|
40
|
-
|
|
41
|
-
> **Talk is cheap.** Let me show you **the code**
|
|
42
|
-
>
|
|
43
|
-
> Link to ๐ [the demo app](https://github.com/tripolskypetr/backtest-kit/tree/master/demo) ๐
|
|
44
|
-
|
|
45
|
-
### ๐ฆ Installation
|
|
46
|
-
```bash
|
|
47
|
-
npm install backtest-kit ccxt ollama uuid
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### โ๏ธ Basic Configuration
|
|
51
|
-
```typescript
|
|
52
|
-
import { setLogger, setConfig } from 'backtest-kit';
|
|
53
|
-
|
|
54
|
-
// Enable logging
|
|
55
|
-
setLogger({
|
|
56
|
-
log: console.log,
|
|
57
|
-
debug: console.debug,
|
|
58
|
-
info: console.info,
|
|
59
|
-
warn: console.warn,
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
// Global config (optional)
|
|
63
|
-
setConfig({
|
|
64
|
-
CC_PERCENT_SLIPPAGE: 0.1, // % slippage
|
|
65
|
-
CC_PERCENT_FEE: 0.1, // % fee
|
|
66
|
-
CC_SCHEDULE_AWAIT_MINUTES: 120, // Pending signal timeout
|
|
67
|
-
});
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
### ๐ง Register Components
|
|
71
|
-
```typescript
|
|
72
|
-
import ccxt from 'ccxt';
|
|
73
|
-
import { addExchange, addStrategy, addFrame, addRisk } from 'backtest-kit';
|
|
74
|
-
|
|
75
|
-
// Exchange (data source)
|
|
76
|
-
addExchange({
|
|
77
|
-
exchangeName: 'binance',
|
|
78
|
-
getCandles: async (symbol, interval, since, limit) => {
|
|
79
|
-
const exchange = new ccxt.binance();
|
|
80
|
-
const ohlcv = await exchange.fetchOHLCV(symbol, interval, since.getTime(), limit);
|
|
81
|
-
return ohlcv.map(([timestamp, open, high, low, close, volume]) => ({ timestamp, open, high, low, close, volume }));
|
|
82
|
-
},
|
|
83
|
-
formatPrice: (symbol, price) => price.toFixed(2),
|
|
84
|
-
formatQuantity: (symbol, quantity) => quantity.toFixed(8),
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Risk profile
|
|
88
|
-
addRisk({
|
|
89
|
-
riskName: 'demo',
|
|
90
|
-
validations: [
|
|
91
|
-
// TP at least 1%
|
|
92
|
-
({ pendingSignal, currentPrice }) => {
|
|
93
|
-
const { priceOpen = currentPrice, priceTakeProfit, position } = pendingSignal;
|
|
94
|
-
const tpDistance = position === 'long' ? ((priceTakeProfit - priceOpen) / priceOpen) * 100 : ((priceOpen - priceTakeProfit) / priceOpen) * 100;
|
|
95
|
-
if (tpDistance < 1) throw new Error(`TP too close: ${tpDistance.toFixed(2)}%`);
|
|
96
|
-
},
|
|
97
|
-
// R/R at least 2:1
|
|
98
|
-
({ pendingSignal, currentPrice }) => {
|
|
99
|
-
const { priceOpen = currentPrice, priceTakeProfit, priceStopLoss, position } = pendingSignal;
|
|
100
|
-
const reward = position === 'long' ? priceTakeProfit - priceOpen : priceOpen - priceTakeProfit;
|
|
101
|
-
const risk = position === 'long' ? priceOpen - priceStopLoss : priceStopLoss - priceOpen;
|
|
102
|
-
if (reward / risk < 2) throw new Error('Poor R/R ratio');
|
|
103
|
-
},
|
|
104
|
-
],
|
|
105
|
-
});
|
|
106
|
-
|
|
107
|
-
// Time frame
|
|
108
|
-
addFrame({
|
|
109
|
-
frameName: '1d-test',
|
|
110
|
-
interval: '1m',
|
|
111
|
-
startDate: new Date('2025-12-01'),
|
|
112
|
-
endDate: new Date('2025-12-02'),
|
|
113
|
-
});
|
|
114
|
-
```
|
|
115
|
-
|
|
116
|
-
### ๐ก Example Strategy (with LLM)
|
|
117
|
-
```typescript
|
|
118
|
-
import { v4 as uuid } from 'uuid';
|
|
119
|
-
import { addStrategy, dumpSignal, getCandles } from 'backtest-kit';
|
|
120
|
-
import { json } from './utils/json.mjs'; // LLM wrapper
|
|
121
|
-
import { getMessages } from './utils/messages.mjs'; // Market data prep
|
|
122
|
-
|
|
123
|
-
addStrategy({
|
|
124
|
-
strategyName: 'llm-strategy',
|
|
125
|
-
interval: '5m',
|
|
126
|
-
riskName: 'demo',
|
|
127
|
-
getSignal: async (symbol) => {
|
|
128
|
-
|
|
129
|
-
const candles1h = await getCandles(symbol, "1h", 24);
|
|
130
|
-
const candles15m = await getCandles(symbol, "15m", 48);
|
|
131
|
-
const candles5m = await getCandles(symbol, "5m", 60);
|
|
132
|
-
const candles1m = await getCandles(symbol, "1m", 60);
|
|
133
|
-
|
|
134
|
-
const messages = await getMessages(symbol, {
|
|
135
|
-
candles1h,
|
|
136
|
-
candles15m,
|
|
137
|
-
candles5m,
|
|
138
|
-
candles1m,
|
|
139
|
-
}); // Calculate indicators / Fetch news
|
|
140
|
-
|
|
141
|
-
const resultId = uuid();
|
|
142
|
-
const signal = await json(messages); // LLM generates signal
|
|
143
|
-
await dumpSignal(resultId, messages, signal); // Log
|
|
144
|
-
|
|
145
|
-
return { ...signal, id: resultId };
|
|
146
|
-
},
|
|
147
|
-
});
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
### ๐งช Run Backtest
|
|
151
|
-
```typescript
|
|
152
|
-
import { Backtest, listenSignalBacktest, listenDoneBacktest } from 'backtest-kit';
|
|
153
|
-
|
|
154
|
-
Backtest.background('BTCUSDT', {
|
|
155
|
-
strategyName: 'llm-strategy',
|
|
156
|
-
exchangeName: 'binance',
|
|
157
|
-
frameName: '1d-test',
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
listenSignalBacktest((event) => console.log(event));
|
|
161
|
-
listenDoneBacktest(async (event) => {
|
|
162
|
-
await Backtest.dump(event.symbol, event.strategyName); // Generate report
|
|
163
|
-
});
|
|
164
|
-
```
|
|
165
|
-
|
|
166
|
-
### ๐ Run Live Trading
|
|
167
|
-
```typescript
|
|
168
|
-
import { Live, listenSignalLive } from 'backtest-kit';
|
|
169
|
-
|
|
170
|
-
Live.background('BTCUSDT', {
|
|
171
|
-
strategyName: 'llm-strategy',
|
|
172
|
-
exchangeName: 'binance', // Use API keys in .env
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
listenSignalLive((event) => console.log(event));
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
### ๐ก Monitoring & Events
|
|
179
|
-
|
|
180
|
-
- Use `listenRisk`, `listenError`, `listenPartialProfit/Loss` for alerts.
|
|
181
|
-
- Dump reports: `Backtest.dump()`, `Live.dump()`.
|
|
182
|
-
|
|
183
|
-
## ๐ Global Configuration
|
|
184
|
-
|
|
185
|
-
Customize via `setConfig()`:
|
|
186
|
-
|
|
187
|
-
- `CC_SCHEDULE_AWAIT_MINUTES`: Pending timeout (default: 120).
|
|
188
|
-
- `CC_AVG_PRICE_CANDLES_COUNT`: VWAP candles (default: 5).
|
|
189
|
-
|
|
190
|
-
## ๐ป Developer Note
|
|
191
|
-
|
|
192
|
-
Backtest Kit is **not a data-processing library** - it is a **time execution engine**. Think of the engine as an **async stream of time**, where your strategy is evaluated step by step.
|
|
193
|
-
|
|
194
|
-
### ๐ How getCandles Works
|
|
195
|
-
|
|
196
|
-
backtest-kit uses Node.js `AsyncLocalStorage` to automatically provide
|
|
197
|
-
temporal time context to your strategies.
|
|
198
|
-
|
|
199
|
-
### ๐ญ What this means:
|
|
200
|
-
- `getCandles()` always returns data UP TO the current backtest timestamp using `async_hooks`
|
|
201
|
-
- Multi-timeframe data is automatically synchronized
|
|
202
|
-
- **Impossible to introduce look-ahead bias**
|
|
203
|
-
- Same code works in both backtest and live modes
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
## ๐ง Two Ways to Run the Engine
|
|
207
|
-
|
|
208
|
-
Backtest Kit exposes the same runtime in two equivalent forms. Both approaches use **the same engine and guarantees** - only the consumption model differs.
|
|
209
|
-
|
|
210
|
-
### 1๏ธโฃ Event-driven (background execution)
|
|
211
|
-
|
|
212
|
-
Suitable for production bots, monitoring, and long-running processes.
|
|
213
|
-
|
|
214
|
-
```typescript
|
|
215
|
-
Backtest.background('BTCUSDT', config);
|
|
216
|
-
|
|
217
|
-
listenSignalBacktest(event => { /* handle signals */ });
|
|
218
|
-
listenDoneBacktest(event => { /* finalize / dump report */ });
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
### 2๏ธโฃ Async Iterator (pull-based execution)
|
|
222
|
-
|
|
223
|
-
Suitable for research, scripting, testing, and LLM agents.
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
for await (const event of Backtest.run('BTCUSDT', config)) {
|
|
227
|
-
// signal | trade | progress | done
|
|
228
|
-
}
|
|
229
|
-
```
|
|
230
|
-
|
|
231
|
-
## โ๏ธ Think of it as...
|
|
232
|
-
|
|
233
|
-
**Open-source QuantConnect without the vendor lock-in**
|
|
234
|
-
|
|
235
|
-
Unlike cloud-based platforms, backtest-kit runs entirely in your environment. You own the entire stack from data ingestion to live execution. In addition to Ollama, you can use [neural-trader](https://www.npmjs.com/package/neural-trader) in `getSignal` function or any other third party library
|
|
236
|
-
|
|
237
|
-
- No C# required - pure TypeScript/JavaScript
|
|
238
|
-
- Self-hosted - your code, your data, your infrastructure
|
|
239
|
-
- No platform fees or hidden costs
|
|
240
|
-
- Full control over execution and data sources
|
|
241
|
-
- [GUI](https://backtest-kit.github.io/documents/design_30_markdown-report-system.html#method-signatures) for visualization and monitoring
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
## ๐ค Are you a robot?
|
|
245
|
-
|
|
246
|
-
**For language models**: Read extended description in [./LLMs.md](./LLMs.md)
|
|
247
|
-
|
|
248
|
-
## โ
Tested & Reliable
|
|
249
|
-
|
|
250
|
-
300+ tests cover validation, recovery, reports, and events.
|
|
251
|
-
|
|
252
|
-
## ๐ค Contribute
|
|
253
|
-
|
|
254
|
-
Fork/PR on [GitHub](https://github.com/tripolskypetr/backtest-kit).
|
|
255
|
-
|
|
256
|
-
## ๐ License
|
|
257
|
-
|
|
258
|
-
MIT ยฉ [tripolskypetr](https://github.com/tripolskypetr)
|
|
259
|
-
|
|
1
|
+
<img src="./assets/triangle.svg" height="105px" align="right">
|
|
2
|
+
|
|
3
|
+
# ๐งฟ Backtest Kit
|
|
4
|
+
|
|
5
|
+
> A TypeScript framework for backtesting and live trading strategies on multi-asset, crypto, forex or [DEX (peer-to-peer marketplace)](https://en.wikipedia.org/wiki/Decentralized_finance#Decentralized_exchanges) with crash-safe persistence, signal validation, and AI optimization.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
[](https://deepwiki.com/tripolskypetr/backtest-kit)
|
|
10
|
+
[](https://npmjs.org/package/backtest-kit)
|
|
11
|
+
[]()
|
|
12
|
+
|
|
13
|
+
Build reliable trading systems: backtest on historical data, deploy live bots with recovery, and optimize strategies using LLMs like Ollama.
|
|
14
|
+
|
|
15
|
+
๐ **[API Reference](https://backtest-kit.github.io/documents/example_02_first_backtest.html)** | ๐ **[Quick Start](https://github.com/tripolskypetr/backtest-kit/tree/master/demo)** | **๐ฐ [Article](https://backtest-kit.github.io/documents/article_02_second_order_chaos.html)**
|
|
16
|
+
|
|
17
|
+
## โจ Why Choose Backtest Kit?
|
|
18
|
+
|
|
19
|
+
- ๐ **Production-Ready**: Seamless switch between backtest/live modes; identical code across environments.
|
|
20
|
+
- ๐พ **Crash-Safe**: Atomic persistence recovers states after crashes, preventing duplicates or losses.
|
|
21
|
+
- โ
**Validation**: Checks signals for TP/SL logic, risk/reward ratios, and portfolio limits.
|
|
22
|
+
- ๐ **Efficient Execution**: Streaming architecture for large datasets; VWAP pricing for realism.
|
|
23
|
+
- ๐ค **AI Integration**: LLM-powered strategy generation (Optimizer) with multi-timeframe analysis.
|
|
24
|
+
- ๐ **Reports & Metrics**: Auto Markdown reports with PNL, Sharpe Ratio, win rate, and more.
|
|
25
|
+
- ๐ก๏ธ **Risk Management**: Custom rules for position limits, time windows, and multi-strategy coordination.
|
|
26
|
+
- ๐ **Pluggable**: Custom data sources (CCXT), persistence (file/Redis), and sizing calculators.
|
|
27
|
+
- ๐งช **Tested**: 300+ unit/integration tests for validation, recovery, and events.
|
|
28
|
+
- ๐ **Self hosted**: Zero dependency on third-party node_modules or platforms; run entirely in your own environment.
|
|
29
|
+
|
|
30
|
+
## ๐ Supported Order Types
|
|
31
|
+
|
|
32
|
+
- Market/Limit entries
|
|
33
|
+
- TP/SL/OCO exits
|
|
34
|
+
- Grid with auto-cancel on unmet conditions
|
|
35
|
+
- Partial profit/loss levels
|
|
36
|
+
- Trailing stop-loss
|
|
37
|
+
- Breakeven protection
|
|
38
|
+
|
|
39
|
+
## ๐ Quick Start
|
|
40
|
+
|
|
41
|
+
> **Talk is cheap.** Let me show you **the code**
|
|
42
|
+
>
|
|
43
|
+
> Link to ๐ [the demo app](https://github.com/tripolskypetr/backtest-kit/tree/master/demo) ๐
|
|
44
|
+
|
|
45
|
+
### ๐ฆ Installation
|
|
46
|
+
```bash
|
|
47
|
+
npm install backtest-kit ccxt ollama uuid
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### โ๏ธ Basic Configuration
|
|
51
|
+
```typescript
|
|
52
|
+
import { setLogger, setConfig } from 'backtest-kit';
|
|
53
|
+
|
|
54
|
+
// Enable logging
|
|
55
|
+
setLogger({
|
|
56
|
+
log: console.log,
|
|
57
|
+
debug: console.debug,
|
|
58
|
+
info: console.info,
|
|
59
|
+
warn: console.warn,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Global config (optional)
|
|
63
|
+
setConfig({
|
|
64
|
+
CC_PERCENT_SLIPPAGE: 0.1, // % slippage
|
|
65
|
+
CC_PERCENT_FEE: 0.1, // % fee
|
|
66
|
+
CC_SCHEDULE_AWAIT_MINUTES: 120, // Pending signal timeout
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### ๐ง Register Components
|
|
71
|
+
```typescript
|
|
72
|
+
import ccxt from 'ccxt';
|
|
73
|
+
import { addExchange, addStrategy, addFrame, addRisk } from 'backtest-kit';
|
|
74
|
+
|
|
75
|
+
// Exchange (data source)
|
|
76
|
+
addExchange({
|
|
77
|
+
exchangeName: 'binance',
|
|
78
|
+
getCandles: async (symbol, interval, since, limit) => {
|
|
79
|
+
const exchange = new ccxt.binance();
|
|
80
|
+
const ohlcv = await exchange.fetchOHLCV(symbol, interval, since.getTime(), limit);
|
|
81
|
+
return ohlcv.map(([timestamp, open, high, low, close, volume]) => ({ timestamp, open, high, low, close, volume }));
|
|
82
|
+
},
|
|
83
|
+
formatPrice: (symbol, price) => price.toFixed(2),
|
|
84
|
+
formatQuantity: (symbol, quantity) => quantity.toFixed(8),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Risk profile
|
|
88
|
+
addRisk({
|
|
89
|
+
riskName: 'demo',
|
|
90
|
+
validations: [
|
|
91
|
+
// TP at least 1%
|
|
92
|
+
({ pendingSignal, currentPrice }) => {
|
|
93
|
+
const { priceOpen = currentPrice, priceTakeProfit, position } = pendingSignal;
|
|
94
|
+
const tpDistance = position === 'long' ? ((priceTakeProfit - priceOpen) / priceOpen) * 100 : ((priceOpen - priceTakeProfit) / priceOpen) * 100;
|
|
95
|
+
if (tpDistance < 1) throw new Error(`TP too close: ${tpDistance.toFixed(2)}%`);
|
|
96
|
+
},
|
|
97
|
+
// R/R at least 2:1
|
|
98
|
+
({ pendingSignal, currentPrice }) => {
|
|
99
|
+
const { priceOpen = currentPrice, priceTakeProfit, priceStopLoss, position } = pendingSignal;
|
|
100
|
+
const reward = position === 'long' ? priceTakeProfit - priceOpen : priceOpen - priceTakeProfit;
|
|
101
|
+
const risk = position === 'long' ? priceOpen - priceStopLoss : priceStopLoss - priceOpen;
|
|
102
|
+
if (reward / risk < 2) throw new Error('Poor R/R ratio');
|
|
103
|
+
},
|
|
104
|
+
],
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// Time frame
|
|
108
|
+
addFrame({
|
|
109
|
+
frameName: '1d-test',
|
|
110
|
+
interval: '1m',
|
|
111
|
+
startDate: new Date('2025-12-01'),
|
|
112
|
+
endDate: new Date('2025-12-02'),
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### ๐ก Example Strategy (with LLM)
|
|
117
|
+
```typescript
|
|
118
|
+
import { v4 as uuid } from 'uuid';
|
|
119
|
+
import { addStrategy, dumpSignal, getCandles } from 'backtest-kit';
|
|
120
|
+
import { json } from './utils/json.mjs'; // LLM wrapper
|
|
121
|
+
import { getMessages } from './utils/messages.mjs'; // Market data prep
|
|
122
|
+
|
|
123
|
+
addStrategy({
|
|
124
|
+
strategyName: 'llm-strategy',
|
|
125
|
+
interval: '5m',
|
|
126
|
+
riskName: 'demo',
|
|
127
|
+
getSignal: async (symbol) => {
|
|
128
|
+
|
|
129
|
+
const candles1h = await getCandles(symbol, "1h", 24);
|
|
130
|
+
const candles15m = await getCandles(symbol, "15m", 48);
|
|
131
|
+
const candles5m = await getCandles(symbol, "5m", 60);
|
|
132
|
+
const candles1m = await getCandles(symbol, "1m", 60);
|
|
133
|
+
|
|
134
|
+
const messages = await getMessages(symbol, {
|
|
135
|
+
candles1h,
|
|
136
|
+
candles15m,
|
|
137
|
+
candles5m,
|
|
138
|
+
candles1m,
|
|
139
|
+
}); // Calculate indicators / Fetch news
|
|
140
|
+
|
|
141
|
+
const resultId = uuid();
|
|
142
|
+
const signal = await json(messages); // LLM generates signal
|
|
143
|
+
await dumpSignal(resultId, messages, signal); // Log
|
|
144
|
+
|
|
145
|
+
return { ...signal, id: resultId };
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### ๐งช Run Backtest
|
|
151
|
+
```typescript
|
|
152
|
+
import { Backtest, listenSignalBacktest, listenDoneBacktest } from 'backtest-kit';
|
|
153
|
+
|
|
154
|
+
Backtest.background('BTCUSDT', {
|
|
155
|
+
strategyName: 'llm-strategy',
|
|
156
|
+
exchangeName: 'binance',
|
|
157
|
+
frameName: '1d-test',
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
listenSignalBacktest((event) => console.log(event));
|
|
161
|
+
listenDoneBacktest(async (event) => {
|
|
162
|
+
await Backtest.dump(event.symbol, event.strategyName); // Generate report
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
### ๐ Run Live Trading
|
|
167
|
+
```typescript
|
|
168
|
+
import { Live, listenSignalLive } from 'backtest-kit';
|
|
169
|
+
|
|
170
|
+
Live.background('BTCUSDT', {
|
|
171
|
+
strategyName: 'llm-strategy',
|
|
172
|
+
exchangeName: 'binance', // Use API keys in .env
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
listenSignalLive((event) => console.log(event));
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### ๐ก Monitoring & Events
|
|
179
|
+
|
|
180
|
+
- Use `listenRisk`, `listenError`, `listenPartialProfit/Loss` for alerts.
|
|
181
|
+
- Dump reports: `Backtest.dump()`, `Live.dump()`.
|
|
182
|
+
|
|
183
|
+
## ๐ Global Configuration
|
|
184
|
+
|
|
185
|
+
Customize via `setConfig()`:
|
|
186
|
+
|
|
187
|
+
- `CC_SCHEDULE_AWAIT_MINUTES`: Pending timeout (default: 120).
|
|
188
|
+
- `CC_AVG_PRICE_CANDLES_COUNT`: VWAP candles (default: 5).
|
|
189
|
+
|
|
190
|
+
## ๐ป Developer Note
|
|
191
|
+
|
|
192
|
+
Backtest Kit is **not a data-processing library** - it is a **time execution engine**. Think of the engine as an **async stream of time**, where your strategy is evaluated step by step.
|
|
193
|
+
|
|
194
|
+
### ๐ How getCandles Works
|
|
195
|
+
|
|
196
|
+
backtest-kit uses Node.js `AsyncLocalStorage` to automatically provide
|
|
197
|
+
temporal time context to your strategies.
|
|
198
|
+
|
|
199
|
+
### ๐ญ What this means:
|
|
200
|
+
- `getCandles()` always returns data UP TO the current backtest timestamp using `async_hooks`
|
|
201
|
+
- Multi-timeframe data is automatically synchronized
|
|
202
|
+
- **Impossible to introduce look-ahead bias**
|
|
203
|
+
- Same code works in both backtest and live modes
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
## ๐ง Two Ways to Run the Engine
|
|
207
|
+
|
|
208
|
+
Backtest Kit exposes the same runtime in two equivalent forms. Both approaches use **the same engine and guarantees** - only the consumption model differs.
|
|
209
|
+
|
|
210
|
+
### 1๏ธโฃ Event-driven (background execution)
|
|
211
|
+
|
|
212
|
+
Suitable for production bots, monitoring, and long-running processes.
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
Backtest.background('BTCUSDT', config);
|
|
216
|
+
|
|
217
|
+
listenSignalBacktest(event => { /* handle signals */ });
|
|
218
|
+
listenDoneBacktest(event => { /* finalize / dump report */ });
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 2๏ธโฃ Async Iterator (pull-based execution)
|
|
222
|
+
|
|
223
|
+
Suitable for research, scripting, testing, and LLM agents.
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
for await (const event of Backtest.run('BTCUSDT', config)) {
|
|
227
|
+
// signal | trade | progress | done
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## โ๏ธ Think of it as...
|
|
232
|
+
|
|
233
|
+
**Open-source QuantConnect without the vendor lock-in**
|
|
234
|
+
|
|
235
|
+
Unlike cloud-based platforms, backtest-kit runs entirely in your environment. You own the entire stack from data ingestion to live execution. In addition to Ollama, you can use [neural-trader](https://www.npmjs.com/package/neural-trader) in `getSignal` function or any other third party library
|
|
236
|
+
|
|
237
|
+
- No C# required - pure TypeScript/JavaScript
|
|
238
|
+
- Self-hosted - your code, your data, your infrastructure
|
|
239
|
+
- No platform fees or hidden costs
|
|
240
|
+
- Full control over execution and data sources
|
|
241
|
+
- [GUI](https://backtest-kit.github.io/documents/design_30_markdown-report-system.html#method-signatures) for visualization and monitoring
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
## ๐ค Are you a robot?
|
|
245
|
+
|
|
246
|
+
**For language models**: Read extended description in [./LLMs.md](./LLMs.md)
|
|
247
|
+
|
|
248
|
+
## โ
Tested & Reliable
|
|
249
|
+
|
|
250
|
+
300+ tests cover validation, recovery, reports, and events.
|
|
251
|
+
|
|
252
|
+
## ๐ค Contribute
|
|
253
|
+
|
|
254
|
+
Fork/PR on [GitHub](https://github.com/tripolskypetr/backtest-kit).
|
|
255
|
+
|
|
256
|
+
## ๐ License
|
|
257
|
+
|
|
258
|
+
MIT ยฉ [tripolskypetr](https://github.com/tripolskypetr)
|
|
259
|
+
|