@backtest-kit/pinets 0.0.3 → 0.0.4

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 CHANGED
@@ -47,22 +47,22 @@ Create a Pine Script file (`strategy.pine`):
47
47
 
48
48
  ```pine
49
49
  //@version=5
50
- indicator("Signal Strategy")
50
+ indicator("Signal Strategy 100 candles of 1H timeframe")
51
51
 
52
- // Indicators
53
- rsi = ta.rsi(close, 14)
54
- atr = ta.atr(14)
55
- ema_fast = ta.ema(close, 9)
56
- ema_slow = ta.ema(close, 21)
52
+ // Indicators - faster settings for 1H
53
+ rsi = ta.rsi(close, 10)
54
+ atr = ta.atr(10)
55
+ ema_fast = ta.ema(close, 7)
56
+ ema_slow = ta.ema(close, 16)
57
57
 
58
58
  // Conditions
59
- long_cond = ta.crossover(ema_fast, ema_slow) and rsi < 70
60
- short_cond = ta.crossunder(ema_fast, ema_slow) and rsi > 30
59
+ long_cond = ta.crossover(ema_fast, ema_slow) and rsi < 65
60
+ short_cond = ta.crossunder(ema_fast, ema_slow) and rsi > 35
61
61
 
62
- // Levels
63
- sl_long = close - atr * 2
62
+ // Levels - tighter SL, wider TP for better RR
63
+ sl_long = close - atr * 1.5
64
64
  tp_long = close + atr * 3
65
- sl_short = close + atr * 2
65
+ sl_short = close + atr * 1.5
66
66
  tp_short = close - atr * 3
67
67
 
68
68
  // Plots for extraction
@@ -70,7 +70,7 @@ plot(close, "Close")
70
70
  plot(long_cond ? 1 : short_cond ? -1 : 0, "Signal")
71
71
  plot(long_cond ? sl_long : sl_short, "StopLoss")
72
72
  plot(long_cond ? tp_long : tp_short, "TakeProfit")
73
- plot(240, "EstimatedTime") // 4 hours in minutes
73
+ plot(60, "EstimatedTime") // 1 hour in minutes
74
74
  ```
75
75
 
76
76
  Use it in your strategy:
@@ -88,7 +88,7 @@ addStrategy({
88
88
 
89
89
  return await getSignal(source, {
90
90
  symbol,
91
- timeframe: '5m',
91
+ timeframe: '1h',
92
92
  limit: 100,
93
93
  });
94
94
  }
@@ -131,28 +131,29 @@ const signal = await getSignal(source, {
131
131
  For advanced use cases, extract any Pine `plot()` with custom mapping:
132
132
 
133
133
  ```typescript
134
- import { File, run } from '@backtest-kit/pinets';
134
+ import { File, run, extract } from '@backtest-kit/pinets';
135
135
 
136
136
  const source = File.fromPath('indicators.pine');
137
137
 
138
- const data = await run(source, {
138
+ const plots = await run(source, {
139
139
  symbol: 'ETHUSDT',
140
140
  timeframe: '1h',
141
141
  limit: 200,
142
- mapping: {
143
- // Simple: plot name -> number
144
- rsi: 'RSI',
145
- macd: 'MACD',
146
-
147
- // Advanced: with transform and lookback
148
- prevRsi: {
149
- plot: 'RSI',
150
- barsBack: 1, // Previous bar value
151
- },
152
- trendStrength: {
153
- plot: 'ADX',
154
- transform: (v) => v > 25 ? 'strong' : 'weak',
155
- },
142
+ });
143
+
144
+ const data = extract(plots, {
145
+ // Simple: plot name -> number
146
+ rsi: 'RSI',
147
+ macd: 'MACD',
148
+
149
+ // Advanced: with transform and lookback
150
+ prevRsi: {
151
+ plot: 'RSI',
152
+ barsBack: 1, // Previous bar value
153
+ },
154
+ trendStrength: {
155
+ plot: 'ADX',
156
+ transform: (v) => v > 25 ? 'strong' : 'weak',
156
157
  },
157
158
  });
158
159
 
package/build/index.cjs CHANGED
@@ -536,12 +536,12 @@ class PineMarkdownService {
536
536
  });
537
537
  const keys = Object.keys(plots);
538
538
  if (keys.length === 0) {
539
- return;
539
+ return [];
540
540
  }
541
541
  const firstPlot = plots[keys[0]];
542
542
  const dataLength = firstPlot?.data?.length ?? 0;
543
543
  if (dataLength === 0) {
544
- return;
544
+ return [];
545
545
  }
546
546
  const rows = [];
547
547
  let warmupComplete = false;
@@ -655,7 +655,7 @@ function usePine(ctor) {
655
655
  pine.pineConnectionService.usePine(ctor);
656
656
  }
657
657
 
658
- const METHOD_NAME_RUN$1 = "run.run";
658
+ const METHOD_NAME_RUN$2 = "run.run";
659
659
  const GET_SOURCE_FN$1 = async (source) => {
660
660
  if (File.isFile(source)) {
661
661
  const code = await pine.pineCacheService.readFile(source.path, source.baseDir);
@@ -666,16 +666,23 @@ const GET_SOURCE_FN$1 = async (source) => {
666
666
  }
667
667
  throw new Error("Source must be a File or Code instance");
668
668
  };
669
- async function run(source, { symbol, timeframe, mapping, limit }) {
670
- pine.loggerService.info(METHOD_NAME_RUN$1, {
669
+ async function run(source, { symbol, timeframe, limit }) {
670
+ pine.loggerService.info(METHOD_NAME_RUN$2, {
671
671
  source,
672
672
  symbol,
673
673
  timeframe,
674
- mapping,
675
674
  limit,
676
675
  });
677
676
  const script = await GET_SOURCE_FN$1(source);
678
677
  const { plots } = await pine.pineJobService.run(script, symbol, timeframe, limit);
678
+ return plots;
679
+ }
680
+
681
+ const METHOD_NAME_RUN$1 = "extract.extract";
682
+ async function extract(plots, mapping) {
683
+ pine.loggerService.info(METHOD_NAME_RUN$1, {
684
+ mapping,
685
+ });
679
686
  return pine.pineDataService.extract(plots, mapping);
680
687
  }
681
688
 
@@ -741,7 +748,7 @@ async function getSignal(source, { symbol, timeframe, limit }) {
741
748
  }
742
749
 
743
750
  const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
744
- async function dumpPineData(signalId, plots, taName, outputDir = "./dump/ta") {
751
+ async function dumpPlotData(signalId, plots, taName, outputDir = "./dump/ta") {
745
752
  pine.loggerService.log(DUMP_SIGNAL_METHOD_NAME, {
746
753
  signalId,
747
754
  plotCount: Object.keys(plots).length,
@@ -753,7 +760,8 @@ async function dumpPineData(signalId, plots, taName, outputDir = "./dump/ta") {
753
760
  exports.AXIS_SYMBOL = AXIS_SYMBOL;
754
761
  exports.Code = Code;
755
762
  exports.File = File;
756
- exports.dumpPineData = dumpPineData;
763
+ exports.dumpPlotData = dumpPlotData;
764
+ exports.extract = extract;
757
765
  exports.getSignal = getSignal;
758
766
  exports.lib = pine;
759
767
  exports.run = run;
package/build/index.mjs CHANGED
@@ -533,12 +533,12 @@ class PineMarkdownService {
533
533
  });
534
534
  const keys = Object.keys(plots);
535
535
  if (keys.length === 0) {
536
- return;
536
+ return [];
537
537
  }
538
538
  const firstPlot = plots[keys[0]];
539
539
  const dataLength = firstPlot?.data?.length ?? 0;
540
540
  if (dataLength === 0) {
541
- return;
541
+ return [];
542
542
  }
543
543
  const rows = [];
544
544
  let warmupComplete = false;
@@ -652,7 +652,7 @@ function usePine(ctor) {
652
652
  pine.pineConnectionService.usePine(ctor);
653
653
  }
654
654
 
655
- const METHOD_NAME_RUN$1 = "run.run";
655
+ const METHOD_NAME_RUN$2 = "run.run";
656
656
  const GET_SOURCE_FN$1 = async (source) => {
657
657
  if (File.isFile(source)) {
658
658
  const code = await pine.pineCacheService.readFile(source.path, source.baseDir);
@@ -663,16 +663,23 @@ const GET_SOURCE_FN$1 = async (source) => {
663
663
  }
664
664
  throw new Error("Source must be a File or Code instance");
665
665
  };
666
- async function run(source, { symbol, timeframe, mapping, limit }) {
667
- pine.loggerService.info(METHOD_NAME_RUN$1, {
666
+ async function run(source, { symbol, timeframe, limit }) {
667
+ pine.loggerService.info(METHOD_NAME_RUN$2, {
668
668
  source,
669
669
  symbol,
670
670
  timeframe,
671
- mapping,
672
671
  limit,
673
672
  });
674
673
  const script = await GET_SOURCE_FN$1(source);
675
674
  const { plots } = await pine.pineJobService.run(script, symbol, timeframe, limit);
675
+ return plots;
676
+ }
677
+
678
+ const METHOD_NAME_RUN$1 = "extract.extract";
679
+ async function extract(plots, mapping) {
680
+ pine.loggerService.info(METHOD_NAME_RUN$1, {
681
+ mapping,
682
+ });
676
683
  return pine.pineDataService.extract(plots, mapping);
677
684
  }
678
685
 
@@ -738,7 +745,7 @@ async function getSignal(source, { symbol, timeframe, limit }) {
738
745
  }
739
746
 
740
747
  const DUMP_SIGNAL_METHOD_NAME = "dump.dumpSignal";
741
- async function dumpPineData(signalId, plots, taName, outputDir = "./dump/ta") {
748
+ async function dumpPlotData(signalId, plots, taName, outputDir = "./dump/ta") {
742
749
  pine.loggerService.log(DUMP_SIGNAL_METHOD_NAME, {
743
750
  signalId,
744
751
  plotCount: Object.keys(plots).length,
@@ -747,4 +754,4 @@ async function dumpPineData(signalId, plots, taName, outputDir = "./dump/ta") {
747
754
  return await pine.pineMarkdownService.dump(signalId, plots, taName, outputDir);
748
755
  }
749
756
 
750
- export { AXIS_SYMBOL, Code, File, dumpPineData, getSignal, pine as lib, run, setLogger, usePine };
757
+ export { AXIS_SYMBOL, Code, File, dumpPlotData, extract, getSignal, pine as lib, run, setLogger, usePine };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backtest-kit/pinets",
3
- "version": "0.0.3",
3
+ "version": "0.0.4",
4
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
5
  "author": {
6
6
  "name": "Petr Tripolsky",
package/types.d.ts CHANGED
@@ -42,6 +42,13 @@ interface IPine {
42
42
 
43
43
  declare function usePine<T = TPineCtor>(ctor: T): void;
44
44
 
45
+ interface IRunParams {
46
+ symbol: string;
47
+ timeframe: CandleInterval;
48
+ limit: number;
49
+ }
50
+ declare function run(source: File | Code, { symbol, timeframe, limit }: IRunParams): Promise<PlotModel>;
51
+
45
52
  type PlotExtractConfig<T = number> = {
46
53
  plot: string;
47
54
  barsBack?: number;
@@ -58,13 +65,7 @@ declare class PineDataService {
58
65
  extract<M extends PlotMapping>(plots: PlotModel, mapping: M): ExtractedData<M>;
59
66
  }
60
67
 
61
- interface IRunParams<M extends PlotMapping> {
62
- symbol: string;
63
- timeframe: CandleInterval;
64
- limit: number;
65
- mapping: M;
66
- }
67
- declare function run<M extends PlotMapping>(source: File | Code, { symbol, timeframe, mapping, limit }: IRunParams<M>): Promise<ExtractedData<M>>;
68
+ declare function extract<M extends PlotMapping>(plots: PlotModel, mapping: M): Promise<ExtractedData<M>>;
68
69
 
69
70
  interface ILogger {
70
71
  log(topic: string, ...args: any[]): void;
@@ -83,7 +84,7 @@ interface IParams {
83
84
  declare function getSignal(source: File | Code, { symbol, timeframe, limit }: IParams): Promise<ISignalDto | null>;
84
85
 
85
86
  type ResultId$1 = string | number;
86
- declare function dumpPineData(signalId: ResultId$1, plots: PlotModel, taName: string, outputDir?: string): Promise<void>;
87
+ declare function dumpPlotData(signalId: ResultId$1, plots: PlotModel, taName: string, outputDir?: string): Promise<void>;
87
88
 
88
89
  interface CandleModel {
89
90
  openTime: number;
@@ -171,4 +172,4 @@ declare const pine: {
171
172
  loggerService: LoggerService;
172
173
  };
173
174
 
174
- export { AXIS_SYMBOL, type CandleModel, Code, File, type ILogger, type IPine, type IProvider, type PlotExtractConfig, type PlotMapping, type PlotModel, type PlotRecord, type SymbolInfoModel, type TPineCtor, dumpPineData, getSignal, pine as lib, run, setLogger, usePine };
175
+ export { AXIS_SYMBOL, type CandleModel, Code, File, type ILogger, type IPine, type IProvider, type PlotExtractConfig, type PlotMapping, type PlotModel, type PlotRecord, type SymbolInfoModel, type TPineCtor, dumpPlotData, extract, getSignal, pine as lib, run, setLogger, usePine };