@backtest-kit/pinets 7.8.0 β 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +319 -319
- package/package.json +89 -89
package/README.md
CHANGED
|
@@ -1,319 +1,319 @@
|
|
|
1
|
-
<img src="https://github.com/tripolskypetr/backtest-kit/raw/refs/heads/master/assets/heraldry.svg" height="45px" align="right">
|
|
2
|
-
|
|
3
|
-
# π @backtest-kit/pinets
|
|
4
|
-
|
|
5
|
-
> Run TradingView Pine Script strategies in Node.js self hosted enviroment. Execute your existing Pine Script indicators and generate trading signals - pure technical analysis with 1:1 syntax compatibility.
|
|
6
|
-
|
|
7
|
-

|
|
8
|
-
|
|
9
|
-
[](https://deepwiki.com/tripolskypetr/backtest-kit)
|
|
10
|
-
[](https://npmjs.org/package/@backtest-kit/pinets)
|
|
11
|
-
[]()
|
|
12
|
-
|
|
13
|
-
Port your TradingView strategies to backtest-kit with zero rewrite. Powered by [PineTS](https://github.com/QuantForgeOrg/PineTS) - an open-source Pine Script transpiler and runtime.
|
|
14
|
-
|
|
15
|
-
π **[Backtest Kit Docs](https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html)** | π **[GitHub](https://github.com/tripolskypetr/backtest-kit)** | π **[PineTS Docs](https://quantforgeorg.github.io/PineTS/)**
|
|
16
|
-
|
|
17
|
-
> **New to backtest-kit?** The fastest way to get a real, production-ready setup is to clone the [reference implementation](https://github.com/tripolskypetr/backtest-kit/tree/master/example) β 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.
|
|
18
|
-
|
|
19
|
-
## β¨ Features
|
|
20
|
-
|
|
21
|
-
- π **Pine Script v5/v6**: Native TradingView syntax with 1:1 compatibility
|
|
22
|
-
- π― **60+ Indicators**: SMA, EMA, RSI, MACD, Bollinger Bands, ATR, Stochastic, and more
|
|
23
|
-
- π **Backtest Integration**: Seamless `getCandles` integration with temporal context
|
|
24
|
-
- π **File or Code**: Load `.pine` files or pass code strings directly
|
|
25
|
-
- πΊοΈ **Plot Extraction**: Flexible mapping from Pine `plot()` outputs to structured data
|
|
26
|
-
- β‘ **Cached Execution**: Memoized file reads for repeated strategy runs
|
|
27
|
-
- π‘οΈ **Type Safe**: Full TypeScript support with generics for extracted data
|
|
28
|
-
|
|
29
|
-
## π What It Does
|
|
30
|
-
|
|
31
|
-
`@backtest-kit/pinets` executes TradingView Pine Script and extracts trading signals for backtest-kit:
|
|
32
|
-
|
|
33
|
-
| Function | Description |
|
|
34
|
-
|----------|-------------|
|
|
35
|
-
| **`getSignal()`** | Run Pine Script and get structured `ISignalDto` (position, TP/SL, estimated time) |
|
|
36
|
-
| **`run()`** | Run Pine Script and return raw plot data |
|
|
37
|
-
| **`extract()`** | Extract the latest bar values from plots with custom mapping |
|
|
38
|
-
| **`extractRows()`** | Extract all bars as a timestamped row array with custom mapping |
|
|
39
|
-
| **`dumpPlotData()`** | Dump plot data to markdown files for debugging |
|
|
40
|
-
| **`usePine()`** | Register custom Pine constructor |
|
|
41
|
-
| **`setLogger()`** | Configure custom logger |
|
|
42
|
-
| **`File.fromPath()`** | Load Pine Script from `.pine` file |
|
|
43
|
-
| **`Code.fromString()`** | Use inline Pine Script code |
|
|
44
|
-
|
|
45
|
-
## π Installation
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
npm install @backtest-kit/pinets pinets backtest-kit
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
## π Usage
|
|
52
|
-
|
|
53
|
-
### Quick Start - Pine Script Strategy
|
|
54
|
-
|
|
55
|
-
Create a Pine Script file (`strategy.pine`):
|
|
56
|
-
|
|
57
|
-
```pine
|
|
58
|
-
//@version=5
|
|
59
|
-
indicator("Signal Strategy 100 candles of 1H timeframe")
|
|
60
|
-
|
|
61
|
-
// Indicators - faster settings for 1H
|
|
62
|
-
rsi = ta.rsi(close, 10)
|
|
63
|
-
atr = ta.atr(10)
|
|
64
|
-
ema_fast = ta.ema(close, 7)
|
|
65
|
-
ema_slow = ta.ema(close, 16)
|
|
66
|
-
|
|
67
|
-
// Conditions
|
|
68
|
-
long_cond = ta.crossover(ema_fast, ema_slow) and rsi < 65
|
|
69
|
-
short_cond = ta.crossunder(ema_fast, ema_slow) and rsi > 35
|
|
70
|
-
|
|
71
|
-
// Levels - tighter SL, wider TP for better RR
|
|
72
|
-
sl_long = close - atr * 1.5
|
|
73
|
-
tp_long = close + atr * 3
|
|
74
|
-
sl_short = close + atr * 1.5
|
|
75
|
-
tp_short = close - atr * 3
|
|
76
|
-
|
|
77
|
-
// Plots for extraction
|
|
78
|
-
plot(close, "Close")
|
|
79
|
-
plot(long_cond ? 1 : short_cond ? -1 : 0, "Signal")
|
|
80
|
-
plot(long_cond ? sl_long : sl_short, "StopLoss")
|
|
81
|
-
plot(long_cond ? tp_long : tp_short, "TakeProfit")
|
|
82
|
-
plot(60, "EstimatedTime") // 1 hour in minutes
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Use it in your strategy:
|
|
86
|
-
|
|
87
|
-
```typescript
|
|
88
|
-
import { File, getSignal } from '@backtest-kit/pinets';
|
|
89
|
-
import { addStrategy } from 'backtest-kit';
|
|
90
|
-
|
|
91
|
-
addStrategy({
|
|
92
|
-
strategyName: 'pine-ema-cross',
|
|
93
|
-
interval: '5m',
|
|
94
|
-
riskName: 'demo',
|
|
95
|
-
getSignal: async (symbol) => {
|
|
96
|
-
const source = File.fromPath('strategy.pine');
|
|
97
|
-
|
|
98
|
-
return await getSignal(source, {
|
|
99
|
-
symbol,
|
|
100
|
-
timeframe: '1h',
|
|
101
|
-
limit: 100,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
});
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Inline Code Strategy
|
|
108
|
-
|
|
109
|
-
No file needed - pass Pine Script as a string:
|
|
110
|
-
|
|
111
|
-
```typescript
|
|
112
|
-
import { Code, getSignal } from '@backtest-kit/pinets';
|
|
113
|
-
|
|
114
|
-
const pineScript = `
|
|
115
|
-
//@version=5
|
|
116
|
-
indicator("RSI Strategy")
|
|
117
|
-
|
|
118
|
-
rsi = ta.rsi(close, 14)
|
|
119
|
-
atr = ta.atr(14)
|
|
120
|
-
|
|
121
|
-
long_cond = rsi < 30
|
|
122
|
-
short_cond = rsi > 70
|
|
123
|
-
|
|
124
|
-
plot(close, "Close")
|
|
125
|
-
plot(long_cond ? 1 : short_cond ? -1 : 0, "Signal")
|
|
126
|
-
plot(close - atr * 2, "StopLoss")
|
|
127
|
-
plot(close + atr * 3, "TakeProfit")
|
|
128
|
-
`;
|
|
129
|
-
|
|
130
|
-
const source = Code.fromString(pineScript);
|
|
131
|
-
const signal = await getSignal(source, {
|
|
132
|
-
symbol: 'BTCUSDT',
|
|
133
|
-
timeframe: '15m',
|
|
134
|
-
limit: 100,
|
|
135
|
-
});
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Custom Plot Extraction
|
|
139
|
-
|
|
140
|
-
For advanced use cases, extract any Pine `plot()` with custom mapping:
|
|
141
|
-
|
|
142
|
-
```typescript
|
|
143
|
-
import { File, run, extract } from '@backtest-kit/pinets';
|
|
144
|
-
|
|
145
|
-
const source = File.fromPath('indicators.pine');
|
|
146
|
-
|
|
147
|
-
const plots = await run(source, {
|
|
148
|
-
symbol: 'ETHUSDT',
|
|
149
|
-
timeframe: '1h',
|
|
150
|
-
limit: 200,
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
const data = await extract(plots, {
|
|
154
|
-
// Simple: plot name -> number
|
|
155
|
-
rsi: 'RSI',
|
|
156
|
-
macd: 'MACD',
|
|
157
|
-
|
|
158
|
-
// Advanced: with transform and lookback
|
|
159
|
-
prevRsi: {
|
|
160
|
-
plot: 'RSI',
|
|
161
|
-
barsBack: 1, // Previous bar value
|
|
162
|
-
},
|
|
163
|
-
trendStrength: {
|
|
164
|
-
plot: 'ADX',
|
|
165
|
-
transform: (v) => v > 25 ? 'strong' : 'weak',
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
// data = { rsi: 55.2, macd: 12.5, prevRsi: 52.1, trendStrength: 'strong' }
|
|
170
|
-
```
|
|
171
|
-
|
|
172
|
-
### Historical Rows Extraction
|
|
173
|
-
|
|
174
|
-
`extractRows()` returns **every bar** as a typed row with a `timestamp` field β useful for building datasets, detecting crossovers across history, or feeding data into downstream analysis.
|
|
175
|
-
|
|
176
|
-
```typescript
|
|
177
|
-
import { File, run, extractRows } from '@backtest-kit/pinets';
|
|
178
|
-
|
|
179
|
-
const source = File.fromPath('indicators.pine');
|
|
180
|
-
|
|
181
|
-
const plots = await run(source, {
|
|
182
|
-
symbol: 'ETHUSDT',
|
|
183
|
-
timeframe: '1h',
|
|
184
|
-
limit: 200,
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
const rows = await extractRows(plots, {
|
|
188
|
-
// Simple: plot name -> number | null
|
|
189
|
-
rsi: 'RSI',
|
|
190
|
-
macd: 'MACD',
|
|
191
|
-
|
|
192
|
-
// Advanced: with lookback and optional transform
|
|
193
|
-
prevRsi: {
|
|
194
|
-
plot: 'RSI',
|
|
195
|
-
barsBack: 1,
|
|
196
|
-
},
|
|
197
|
-
trend: {
|
|
198
|
-
plot: 'ADX',
|
|
199
|
-
transform: (v) => v > 25 ? 'strong' : 'weak',
|
|
200
|
-
},
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
// rows[0] = { timestamp: '2024-01-01T00:00:00.000Z', rsi: 48.3, macd: -2.1, prevRsi: null, trend: 'weak' }
|
|
204
|
-
// rows[1] = { timestamp: '2024-01-01T01:00:00.000Z', rsi: 52.1, macd: -1.5, prevRsi: 48.3, trend: 'weak' }
|
|
205
|
-
// ...
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
**Difference between `extract()` and `extractRows()`:**
|
|
209
|
-
|
|
210
|
-
| | `extract()` | `extractRows()` |
|
|
211
|
-
|---|---|---|
|
|
212
|
-
| Returns | Single object (latest bar) | Array of objects (all bars) |
|
|
213
|
-
| Missing value | `0` (fallback) | `null` |
|
|
214
|
-
| `timestamp` field | No | Yes β ISO string from the bar's time |
|
|
215
|
-
| `barsBack` | Looks back from the last bar | Looks back from each bar's own index |
|
|
216
|
-
| Use case | Signal generation at current bar | Dataset export, historical analysis |
|
|
217
|
-
|
|
218
|
-
### Debug with Plot Dump
|
|
219
|
-
|
|
220
|
-
Dump plot data to markdown files for analysis and debugging:
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
import { File, run, dumpPlotData } from '@backtest-kit/pinets';
|
|
224
|
-
|
|
225
|
-
const source = File.fromPath('strategy.pine');
|
|
226
|
-
|
|
227
|
-
const plots = await run(source, {
|
|
228
|
-
symbol: 'BTCUSDT',
|
|
229
|
-
timeframe: '1h',
|
|
230
|
-
limit: 100,
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
// Dump plots to ./dump/ta directory
|
|
234
|
-
await dumpPlotData('signal-001', plots, 'ema-cross', './dump/ta');
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
### Custom Pine Constructor
|
|
238
|
-
|
|
239
|
-
Register a custom Pine constructor for advanced configurations:
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
import { usePine } from '@backtest-kit/pinets';
|
|
243
|
-
import { Pine } from 'pinets';
|
|
244
|
-
|
|
245
|
-
// Use custom Pine instance
|
|
246
|
-
usePine(Pine);
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
### Custom Logger
|
|
250
|
-
|
|
251
|
-
Configure logging for debugging:
|
|
252
|
-
|
|
253
|
-
```typescript
|
|
254
|
-
import { setLogger } from '@backtest-kit/pinets';
|
|
255
|
-
|
|
256
|
-
setLogger({
|
|
257
|
-
log: (method, data) => console.log(`[${method}]`, data),
|
|
258
|
-
info: (method, data) => console.info(`[${method}]`, data),
|
|
259
|
-
error: (method, data) => console.error(`[${method}]`, data),
|
|
260
|
-
});
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
## π Pine Script Conventions
|
|
264
|
-
|
|
265
|
-
For `getSignal()` to work, your Pine Script must include these plots:
|
|
266
|
-
|
|
267
|
-
| Plot Name | Value | Description |
|
|
268
|
-
|-----------|-------|-------------|
|
|
269
|
-
| `"Signal"` | `1` / `-1` / `0` | Long / Short / No signal |
|
|
270
|
-
| `"Close"` | `close` | Entry price |
|
|
271
|
-
| `"StopLoss"` | price | Stop loss level |
|
|
272
|
-
| `"TakeProfit"` | price | Take profit level |
|
|
273
|
-
| `"EstimatedTime"` | minutes | Hold duration (optional, default: 240) |
|
|
274
|
-
|
|
275
|
-
Using custom plots is also possible with `run`, it allows to reconfigure the mapper
|
|
276
|
-
|
|
277
|
-
## π‘ Why Use @backtest-kit/pinets?
|
|
278
|
-
|
|
279
|
-
Instead of rewriting your TradingView strategies:
|
|
280
|
-
|
|
281
|
-
```typescript
|
|
282
|
-
// β Without pinets (manual rewrite)
|
|
283
|
-
import { getCandles } from 'backtest-kit';
|
|
284
|
-
import { RSI, EMA, ATR } from 'technicalindicators';
|
|
285
|
-
|
|
286
|
-
const candles = await getCandles('BTCUSDT', '5m', 100);
|
|
287
|
-
const closes = candles.map(c => c.close);
|
|
288
|
-
const rsi = RSI.calculate({ values: closes, period: 14 });
|
|
289
|
-
const emaFast = EMA.calculate({ values: closes, period: 9 });
|
|
290
|
-
const emaSlow = EMA.calculate({ values: closes, period: 21 });
|
|
291
|
-
// ... rewrite all your Pine Script logic in JS
|
|
292
|
-
```
|
|
293
|
-
|
|
294
|
-
```typescript
|
|
295
|
-
// β
With pinets (copy-paste from TradingView)
|
|
296
|
-
import { File, getSignal } from '@backtest-kit/pinets';
|
|
297
|
-
|
|
298
|
-
const signal = await getSignal(File.fromPath('strategy.pine'), {
|
|
299
|
-
symbol: 'BTCUSDT',
|
|
300
|
-
timeframe: '5m',
|
|
301
|
-
limit: 100,
|
|
302
|
-
});
|
|
303
|
-
```
|
|
304
|
-
|
|
305
|
-
**Benefits:**
|
|
306
|
-
|
|
307
|
-
- π Use existing TradingView Pine Script as-is
|
|
308
|
-
- π― 60+ built-in indicators (no manual calculation)
|
|
309
|
-
- β‘ Same code for backtest and live trading
|
|
310
|
-
- π Full time-series semantics with lookback support
|
|
311
|
-
- π‘οΈ Type-safe extraction with TypeScript generics
|
|
312
|
-
|
|
313
|
-
## π€ Contribute
|
|
314
|
-
|
|
315
|
-
Fork/PR on [GitHub](https://github.com/tripolskypetr/backtest-kit).
|
|
316
|
-
|
|
317
|
-
## π License
|
|
318
|
-
|
|
319
|
-
MIT Β© [tripolskypetr](https://github.com/tripolskypetr)
|
|
1
|
+
<img src="https://github.com/tripolskypetr/backtest-kit/raw/refs/heads/master/assets/heraldry.svg" height="45px" align="right">
|
|
2
|
+
|
|
3
|
+
# π @backtest-kit/pinets
|
|
4
|
+
|
|
5
|
+
> Run TradingView Pine Script strategies in Node.js self hosted enviroment. Execute your existing Pine Script indicators and generate trading signals - pure technical analysis with 1:1 syntax compatibility.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
[](https://deepwiki.com/tripolskypetr/backtest-kit)
|
|
10
|
+
[](https://npmjs.org/package/@backtest-kit/pinets)
|
|
11
|
+
[]()
|
|
12
|
+
|
|
13
|
+
Port your TradingView strategies to backtest-kit with zero rewrite. Powered by [PineTS](https://github.com/QuantForgeOrg/PineTS) - an open-source Pine Script transpiler and runtime.
|
|
14
|
+
|
|
15
|
+
π **[Backtest Kit Docs](https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html)** | π **[GitHub](https://github.com/tripolskypetr/backtest-kit)** | π **[PineTS Docs](https://quantforgeorg.github.io/PineTS/)**
|
|
16
|
+
|
|
17
|
+
> **New to backtest-kit?** The fastest way to get a real, production-ready setup is to clone the [reference implementation](https://github.com/tripolskypetr/backtest-kit/tree/master/example) β 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.
|
|
18
|
+
|
|
19
|
+
## β¨ Features
|
|
20
|
+
|
|
21
|
+
- π **Pine Script v5/v6**: Native TradingView syntax with 1:1 compatibility
|
|
22
|
+
- π― **60+ Indicators**: SMA, EMA, RSI, MACD, Bollinger Bands, ATR, Stochastic, and more
|
|
23
|
+
- π **Backtest Integration**: Seamless `getCandles` integration with temporal context
|
|
24
|
+
- π **File or Code**: Load `.pine` files or pass code strings directly
|
|
25
|
+
- πΊοΈ **Plot Extraction**: Flexible mapping from Pine `plot()` outputs to structured data
|
|
26
|
+
- β‘ **Cached Execution**: Memoized file reads for repeated strategy runs
|
|
27
|
+
- π‘οΈ **Type Safe**: Full TypeScript support with generics for extracted data
|
|
28
|
+
|
|
29
|
+
## π What It Does
|
|
30
|
+
|
|
31
|
+
`@backtest-kit/pinets` executes TradingView Pine Script and extracts trading signals for backtest-kit:
|
|
32
|
+
|
|
33
|
+
| Function | Description |
|
|
34
|
+
|----------|-------------|
|
|
35
|
+
| **`getSignal()`** | Run Pine Script and get structured `ISignalDto` (position, TP/SL, estimated time) |
|
|
36
|
+
| **`run()`** | Run Pine Script and return raw plot data |
|
|
37
|
+
| **`extract()`** | Extract the latest bar values from plots with custom mapping |
|
|
38
|
+
| **`extractRows()`** | Extract all bars as a timestamped row array with custom mapping |
|
|
39
|
+
| **`dumpPlotData()`** | Dump plot data to markdown files for debugging |
|
|
40
|
+
| **`usePine()`** | Register custom Pine constructor |
|
|
41
|
+
| **`setLogger()`** | Configure custom logger |
|
|
42
|
+
| **`File.fromPath()`** | Load Pine Script from `.pine` file |
|
|
43
|
+
| **`Code.fromString()`** | Use inline Pine Script code |
|
|
44
|
+
|
|
45
|
+
## π Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @backtest-kit/pinets pinets backtest-kit
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## π Usage
|
|
52
|
+
|
|
53
|
+
### Quick Start - Pine Script Strategy
|
|
54
|
+
|
|
55
|
+
Create a Pine Script file (`strategy.pine`):
|
|
56
|
+
|
|
57
|
+
```pine
|
|
58
|
+
//@version=5
|
|
59
|
+
indicator("Signal Strategy 100 candles of 1H timeframe")
|
|
60
|
+
|
|
61
|
+
// Indicators - faster settings for 1H
|
|
62
|
+
rsi = ta.rsi(close, 10)
|
|
63
|
+
atr = ta.atr(10)
|
|
64
|
+
ema_fast = ta.ema(close, 7)
|
|
65
|
+
ema_slow = ta.ema(close, 16)
|
|
66
|
+
|
|
67
|
+
// Conditions
|
|
68
|
+
long_cond = ta.crossover(ema_fast, ema_slow) and rsi < 65
|
|
69
|
+
short_cond = ta.crossunder(ema_fast, ema_slow) and rsi > 35
|
|
70
|
+
|
|
71
|
+
// Levels - tighter SL, wider TP for better RR
|
|
72
|
+
sl_long = close - atr * 1.5
|
|
73
|
+
tp_long = close + atr * 3
|
|
74
|
+
sl_short = close + atr * 1.5
|
|
75
|
+
tp_short = close - atr * 3
|
|
76
|
+
|
|
77
|
+
// Plots for extraction
|
|
78
|
+
plot(close, "Close")
|
|
79
|
+
plot(long_cond ? 1 : short_cond ? -1 : 0, "Signal")
|
|
80
|
+
plot(long_cond ? sl_long : sl_short, "StopLoss")
|
|
81
|
+
plot(long_cond ? tp_long : tp_short, "TakeProfit")
|
|
82
|
+
plot(60, "EstimatedTime") // 1 hour in minutes
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Use it in your strategy:
|
|
86
|
+
|
|
87
|
+
```typescript
|
|
88
|
+
import { File, getSignal } from '@backtest-kit/pinets';
|
|
89
|
+
import { addStrategy } from 'backtest-kit';
|
|
90
|
+
|
|
91
|
+
addStrategy({
|
|
92
|
+
strategyName: 'pine-ema-cross',
|
|
93
|
+
interval: '5m',
|
|
94
|
+
riskName: 'demo',
|
|
95
|
+
getSignal: async (symbol) => {
|
|
96
|
+
const source = File.fromPath('strategy.pine');
|
|
97
|
+
|
|
98
|
+
return await getSignal(source, {
|
|
99
|
+
symbol,
|
|
100
|
+
timeframe: '1h',
|
|
101
|
+
limit: 100,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Inline Code Strategy
|
|
108
|
+
|
|
109
|
+
No file needed - pass Pine Script as a string:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
import { Code, getSignal } from '@backtest-kit/pinets';
|
|
113
|
+
|
|
114
|
+
const pineScript = `
|
|
115
|
+
//@version=5
|
|
116
|
+
indicator("RSI Strategy")
|
|
117
|
+
|
|
118
|
+
rsi = ta.rsi(close, 14)
|
|
119
|
+
atr = ta.atr(14)
|
|
120
|
+
|
|
121
|
+
long_cond = rsi < 30
|
|
122
|
+
short_cond = rsi > 70
|
|
123
|
+
|
|
124
|
+
plot(close, "Close")
|
|
125
|
+
plot(long_cond ? 1 : short_cond ? -1 : 0, "Signal")
|
|
126
|
+
plot(close - atr * 2, "StopLoss")
|
|
127
|
+
plot(close + atr * 3, "TakeProfit")
|
|
128
|
+
`;
|
|
129
|
+
|
|
130
|
+
const source = Code.fromString(pineScript);
|
|
131
|
+
const signal = await getSignal(source, {
|
|
132
|
+
symbol: 'BTCUSDT',
|
|
133
|
+
timeframe: '15m',
|
|
134
|
+
limit: 100,
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### Custom Plot Extraction
|
|
139
|
+
|
|
140
|
+
For advanced use cases, extract any Pine `plot()` with custom mapping:
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
import { File, run, extract } from '@backtest-kit/pinets';
|
|
144
|
+
|
|
145
|
+
const source = File.fromPath('indicators.pine');
|
|
146
|
+
|
|
147
|
+
const plots = await run(source, {
|
|
148
|
+
symbol: 'ETHUSDT',
|
|
149
|
+
timeframe: '1h',
|
|
150
|
+
limit: 200,
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const data = await extract(plots, {
|
|
154
|
+
// Simple: plot name -> number
|
|
155
|
+
rsi: 'RSI',
|
|
156
|
+
macd: 'MACD',
|
|
157
|
+
|
|
158
|
+
// Advanced: with transform and lookback
|
|
159
|
+
prevRsi: {
|
|
160
|
+
plot: 'RSI',
|
|
161
|
+
barsBack: 1, // Previous bar value
|
|
162
|
+
},
|
|
163
|
+
trendStrength: {
|
|
164
|
+
plot: 'ADX',
|
|
165
|
+
transform: (v) => v > 25 ? 'strong' : 'weak',
|
|
166
|
+
},
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// data = { rsi: 55.2, macd: 12.5, prevRsi: 52.1, trendStrength: 'strong' }
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Historical Rows Extraction
|
|
173
|
+
|
|
174
|
+
`extractRows()` returns **every bar** as a typed row with a `timestamp` field β useful for building datasets, detecting crossovers across history, or feeding data into downstream analysis.
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
import { File, run, extractRows } from '@backtest-kit/pinets';
|
|
178
|
+
|
|
179
|
+
const source = File.fromPath('indicators.pine');
|
|
180
|
+
|
|
181
|
+
const plots = await run(source, {
|
|
182
|
+
symbol: 'ETHUSDT',
|
|
183
|
+
timeframe: '1h',
|
|
184
|
+
limit: 200,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const rows = await extractRows(plots, {
|
|
188
|
+
// Simple: plot name -> number | null
|
|
189
|
+
rsi: 'RSI',
|
|
190
|
+
macd: 'MACD',
|
|
191
|
+
|
|
192
|
+
// Advanced: with lookback and optional transform
|
|
193
|
+
prevRsi: {
|
|
194
|
+
plot: 'RSI',
|
|
195
|
+
barsBack: 1,
|
|
196
|
+
},
|
|
197
|
+
trend: {
|
|
198
|
+
plot: 'ADX',
|
|
199
|
+
transform: (v) => v > 25 ? 'strong' : 'weak',
|
|
200
|
+
},
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
// rows[0] = { timestamp: '2024-01-01T00:00:00.000Z', rsi: 48.3, macd: -2.1, prevRsi: null, trend: 'weak' }
|
|
204
|
+
// rows[1] = { timestamp: '2024-01-01T01:00:00.000Z', rsi: 52.1, macd: -1.5, prevRsi: 48.3, trend: 'weak' }
|
|
205
|
+
// ...
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
**Difference between `extract()` and `extractRows()`:**
|
|
209
|
+
|
|
210
|
+
| | `extract()` | `extractRows()` |
|
|
211
|
+
|---|---|---|
|
|
212
|
+
| Returns | Single object (latest bar) | Array of objects (all bars) |
|
|
213
|
+
| Missing value | `0` (fallback) | `null` |
|
|
214
|
+
| `timestamp` field | No | Yes β ISO string from the bar's time |
|
|
215
|
+
| `barsBack` | Looks back from the last bar | Looks back from each bar's own index |
|
|
216
|
+
| Use case | Signal generation at current bar | Dataset export, historical analysis |
|
|
217
|
+
|
|
218
|
+
### Debug with Plot Dump
|
|
219
|
+
|
|
220
|
+
Dump plot data to markdown files for analysis and debugging:
|
|
221
|
+
|
|
222
|
+
```typescript
|
|
223
|
+
import { File, run, dumpPlotData } from '@backtest-kit/pinets';
|
|
224
|
+
|
|
225
|
+
const source = File.fromPath('strategy.pine');
|
|
226
|
+
|
|
227
|
+
const plots = await run(source, {
|
|
228
|
+
symbol: 'BTCUSDT',
|
|
229
|
+
timeframe: '1h',
|
|
230
|
+
limit: 100,
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
// Dump plots to ./dump/ta directory
|
|
234
|
+
await dumpPlotData('signal-001', plots, 'ema-cross', './dump/ta');
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Custom Pine Constructor
|
|
238
|
+
|
|
239
|
+
Register a custom Pine constructor for advanced configurations:
|
|
240
|
+
|
|
241
|
+
```typescript
|
|
242
|
+
import { usePine } from '@backtest-kit/pinets';
|
|
243
|
+
import { Pine } from 'pinets';
|
|
244
|
+
|
|
245
|
+
// Use custom Pine instance
|
|
246
|
+
usePine(Pine);
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Custom Logger
|
|
250
|
+
|
|
251
|
+
Configure logging for debugging:
|
|
252
|
+
|
|
253
|
+
```typescript
|
|
254
|
+
import { setLogger } from '@backtest-kit/pinets';
|
|
255
|
+
|
|
256
|
+
setLogger({
|
|
257
|
+
log: (method, data) => console.log(`[${method}]`, data),
|
|
258
|
+
info: (method, data) => console.info(`[${method}]`, data),
|
|
259
|
+
error: (method, data) => console.error(`[${method}]`, data),
|
|
260
|
+
});
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
## π Pine Script Conventions
|
|
264
|
+
|
|
265
|
+
For `getSignal()` to work, your Pine Script must include these plots:
|
|
266
|
+
|
|
267
|
+
| Plot Name | Value | Description |
|
|
268
|
+
|-----------|-------|-------------|
|
|
269
|
+
| `"Signal"` | `1` / `-1` / `0` | Long / Short / No signal |
|
|
270
|
+
| `"Close"` | `close` | Entry price |
|
|
271
|
+
| `"StopLoss"` | price | Stop loss level |
|
|
272
|
+
| `"TakeProfit"` | price | Take profit level |
|
|
273
|
+
| `"EstimatedTime"` | minutes | Hold duration (optional, default: 240) |
|
|
274
|
+
|
|
275
|
+
Using custom plots is also possible with `run`, it allows to reconfigure the mapper
|
|
276
|
+
|
|
277
|
+
## π‘ Why Use @backtest-kit/pinets?
|
|
278
|
+
|
|
279
|
+
Instead of rewriting your TradingView strategies:
|
|
280
|
+
|
|
281
|
+
```typescript
|
|
282
|
+
// β Without pinets (manual rewrite)
|
|
283
|
+
import { getCandles } from 'backtest-kit';
|
|
284
|
+
import { RSI, EMA, ATR } from 'technicalindicators';
|
|
285
|
+
|
|
286
|
+
const candles = await getCandles('BTCUSDT', '5m', 100);
|
|
287
|
+
const closes = candles.map(c => c.close);
|
|
288
|
+
const rsi = RSI.calculate({ values: closes, period: 14 });
|
|
289
|
+
const emaFast = EMA.calculate({ values: closes, period: 9 });
|
|
290
|
+
const emaSlow = EMA.calculate({ values: closes, period: 21 });
|
|
291
|
+
// ... rewrite all your Pine Script logic in JS
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
```typescript
|
|
295
|
+
// β
With pinets (copy-paste from TradingView)
|
|
296
|
+
import { File, getSignal } from '@backtest-kit/pinets';
|
|
297
|
+
|
|
298
|
+
const signal = await getSignal(File.fromPath('strategy.pine'), {
|
|
299
|
+
symbol: 'BTCUSDT',
|
|
300
|
+
timeframe: '5m',
|
|
301
|
+
limit: 100,
|
|
302
|
+
});
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
**Benefits:**
|
|
306
|
+
|
|
307
|
+
- π Use existing TradingView Pine Script as-is
|
|
308
|
+
- π― 60+ built-in indicators (no manual calculation)
|
|
309
|
+
- β‘ Same code for backtest and live trading
|
|
310
|
+
- π Full time-series semantics with lookback support
|
|
311
|
+
- π‘οΈ Type-safe extraction with TypeScript generics
|
|
312
|
+
|
|
313
|
+
## π€ Contribute
|
|
314
|
+
|
|
315
|
+
Fork/PR on [GitHub](https://github.com/tripolskypetr/backtest-kit).
|
|
316
|
+
|
|
317
|
+
## π License
|
|
318
|
+
|
|
319
|
+
MIT Β© [tripolskypetr](https://github.com/tripolskypetr)
|
package/package.json
CHANGED
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@backtest-kit/pinets",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Run TradingView Pine Script strategies in Node.js self hosted environment. Execute existing Pine Script indicators and generate trading signals with 1:1 syntax compatibility via PineTS runtime.",
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "Petr Tripolsky",
|
|
7
|
-
"email": "tripolskypetr@gmail.com",
|
|
8
|
-
"url": "https://github.com/tripolskypetr"
|
|
9
|
-
},
|
|
10
|
-
"funding": {
|
|
11
|
-
"type": "individual",
|
|
12
|
-
"url": "http://paypal.me/tripolskypetr"
|
|
13
|
-
},
|
|
14
|
-
"license": "MIT",
|
|
15
|
-
"homepage": "https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html",
|
|
16
|
-
"keywords": [
|
|
17
|
-
"pinescript",
|
|
18
|
-
"pine-script",
|
|
19
|
-
"tradingview",
|
|
20
|
-
"pinets",
|
|
21
|
-
"technical-analysis",
|
|
22
|
-
"trading-bot",
|
|
23
|
-
"algorithmic-trading",
|
|
24
|
-
"backtest",
|
|
25
|
-
"backtesting",
|
|
26
|
-
"cryptocurrency",
|
|
27
|
-
"forex",
|
|
28
|
-
"strategy",
|
|
29
|
-
"indicators",
|
|
30
|
-
"rsi",
|
|
31
|
-
"macd",
|
|
32
|
-
"ema",
|
|
33
|
-
"bollinger-bands"
|
|
34
|
-
],
|
|
35
|
-
"files": [
|
|
36
|
-
"build",
|
|
37
|
-
"types.d.ts",
|
|
38
|
-
"README.md"
|
|
39
|
-
],
|
|
40
|
-
"repository": {
|
|
41
|
-
"type": "git",
|
|
42
|
-
"url": "https://github.com/tripolskypetr/backtest-kit",
|
|
43
|
-
"documentation": "https://github.com/tripolskypetr/backtest-kit/tree/master/docs"
|
|
44
|
-
},
|
|
45
|
-
"bugs": {
|
|
46
|
-
"url": "https://github.com/tripolskypetr/backtest-kit/issues"
|
|
47
|
-
},
|
|
48
|
-
"scripts": {
|
|
49
|
-
"build": "rollup -c"
|
|
50
|
-
},
|
|
51
|
-
"main": "build/index.cjs",
|
|
52
|
-
"module": "build/index.mjs",
|
|
53
|
-
"source": "src/index.ts",
|
|
54
|
-
"types": "./types.d.ts",
|
|
55
|
-
"exports": {
|
|
56
|
-
"require": "./build/index.cjs",
|
|
57
|
-
"types": "./types.d.ts",
|
|
58
|
-
"import": "./build/index.mjs",
|
|
59
|
-
"default": "./build/index.cjs"
|
|
60
|
-
},
|
|
61
|
-
"devDependencies": {
|
|
62
|
-
"@rollup/plugin-typescript": "11.1.6",
|
|
63
|
-
"@types/node": "22.9.0",
|
|
64
|
-
"glob": "11.0.1",
|
|
65
|
-
"rimraf": "6.0.1",
|
|
66
|
-
"rollup": "3.29.5",
|
|
67
|
-
"rollup-plugin-dts": "6.1.1",
|
|
68
|
-
"rollup-plugin-peer-deps-external": "2.2.4",
|
|
69
|
-
"ts-morph": "27.0.2",
|
|
70
|
-
"tslib": "2.7.0",
|
|
71
|
-
"typedoc": "0.27.9",
|
|
72
|
-
"backtest-kit": "
|
|
73
|
-
"worker-testbed": "2.0.0"
|
|
74
|
-
},
|
|
75
|
-
"peerDependencies": {
|
|
76
|
-
"backtest-kit": "^
|
|
77
|
-
"pinets": "^0.9.13",
|
|
78
|
-
"typescript": "^5.0.0"
|
|
79
|
-
},
|
|
80
|
-
"dependencies": {
|
|
81
|
-
"di-kit": "^1.1.1",
|
|
82
|
-
"di-scoped": "^1.0.21",
|
|
83
|
-
"functools-kit": "^2.3.0",
|
|
84
|
-
"get-moment-stamp": "^1.1.2"
|
|
85
|
-
},
|
|
86
|
-
"publishConfig": {
|
|
87
|
-
"access": "public"
|
|
88
|
-
}
|
|
89
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@backtest-kit/pinets",
|
|
3
|
+
"version": "8.0.0",
|
|
4
|
+
"description": "Run TradingView Pine Script strategies in Node.js self hosted environment. Execute existing Pine Script indicators and generate trading signals with 1:1 syntax compatibility via PineTS runtime.",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Petr Tripolsky",
|
|
7
|
+
"email": "tripolskypetr@gmail.com",
|
|
8
|
+
"url": "https://github.com/tripolskypetr"
|
|
9
|
+
},
|
|
10
|
+
"funding": {
|
|
11
|
+
"type": "individual",
|
|
12
|
+
"url": "http://paypal.me/tripolskypetr"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"homepage": "https://backtest-kit.github.io/documents/article_07_ai_news_trading_signals.html",
|
|
16
|
+
"keywords": [
|
|
17
|
+
"pinescript",
|
|
18
|
+
"pine-script",
|
|
19
|
+
"tradingview",
|
|
20
|
+
"pinets",
|
|
21
|
+
"technical-analysis",
|
|
22
|
+
"trading-bot",
|
|
23
|
+
"algorithmic-trading",
|
|
24
|
+
"backtest",
|
|
25
|
+
"backtesting",
|
|
26
|
+
"cryptocurrency",
|
|
27
|
+
"forex",
|
|
28
|
+
"strategy",
|
|
29
|
+
"indicators",
|
|
30
|
+
"rsi",
|
|
31
|
+
"macd",
|
|
32
|
+
"ema",
|
|
33
|
+
"bollinger-bands"
|
|
34
|
+
],
|
|
35
|
+
"files": [
|
|
36
|
+
"build",
|
|
37
|
+
"types.d.ts",
|
|
38
|
+
"README.md"
|
|
39
|
+
],
|
|
40
|
+
"repository": {
|
|
41
|
+
"type": "git",
|
|
42
|
+
"url": "https://github.com/tripolskypetr/backtest-kit",
|
|
43
|
+
"documentation": "https://github.com/tripolskypetr/backtest-kit/tree/master/docs"
|
|
44
|
+
},
|
|
45
|
+
"bugs": {
|
|
46
|
+
"url": "https://github.com/tripolskypetr/backtest-kit/issues"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "rollup -c"
|
|
50
|
+
},
|
|
51
|
+
"main": "build/index.cjs",
|
|
52
|
+
"module": "build/index.mjs",
|
|
53
|
+
"source": "src/index.ts",
|
|
54
|
+
"types": "./types.d.ts",
|
|
55
|
+
"exports": {
|
|
56
|
+
"require": "./build/index.cjs",
|
|
57
|
+
"types": "./types.d.ts",
|
|
58
|
+
"import": "./build/index.mjs",
|
|
59
|
+
"default": "./build/index.cjs"
|
|
60
|
+
},
|
|
61
|
+
"devDependencies": {
|
|
62
|
+
"@rollup/plugin-typescript": "11.1.6",
|
|
63
|
+
"@types/node": "22.9.0",
|
|
64
|
+
"glob": "11.0.1",
|
|
65
|
+
"rimraf": "6.0.1",
|
|
66
|
+
"rollup": "3.29.5",
|
|
67
|
+
"rollup-plugin-dts": "6.1.1",
|
|
68
|
+
"rollup-plugin-peer-deps-external": "2.2.4",
|
|
69
|
+
"ts-morph": "27.0.2",
|
|
70
|
+
"tslib": "2.7.0",
|
|
71
|
+
"typedoc": "0.27.9",
|
|
72
|
+
"backtest-kit": "8.0.0",
|
|
73
|
+
"worker-testbed": "2.0.0"
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"backtest-kit": "^8.0.0",
|
|
77
|
+
"pinets": "^0.9.13",
|
|
78
|
+
"typescript": "^5.0.0"
|
|
79
|
+
},
|
|
80
|
+
"dependencies": {
|
|
81
|
+
"di-kit": "^1.1.1",
|
|
82
|
+
"di-scoped": "^1.0.21",
|
|
83
|
+
"functools-kit": "^2.3.0",
|
|
84
|
+
"get-moment-stamp": "^1.1.2"
|
|
85
|
+
},
|
|
86
|
+
"publishConfig": {
|
|
87
|
+
"access": "public"
|
|
88
|
+
}
|
|
89
|
+
}
|