@backtest-kit/pinets 3.0.1 → 3.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/index.cjs +43 -3
- package/build/index.mjs +44 -5
- package/package.json +1 -1
- package/types.d.ts +18 -4
package/build/index.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var path = require('path');
|
|
4
4
|
var backtestKit = require('backtest-kit');
|
|
5
5
|
var diKit = require('di-kit');
|
|
6
|
+
var diScoped = require('di-scoped');
|
|
6
7
|
var functoolsKit = require('functools-kit');
|
|
7
8
|
var fs = require('fs/promises');
|
|
8
9
|
var module$1 = require('module');
|
|
@@ -82,6 +83,7 @@ const { provide, inject, init, override } = diKit.createActivator("pine");
|
|
|
82
83
|
|
|
83
84
|
const baseServices = {
|
|
84
85
|
loggerService: Symbol("loggerService"),
|
|
86
|
+
contextService: Symbol("contextService"),
|
|
85
87
|
};
|
|
86
88
|
const providerServices$1 = {
|
|
87
89
|
axisProviderService: Symbol("axisProviderService"),
|
|
@@ -230,9 +232,28 @@ class AxisProviderService {
|
|
|
230
232
|
}
|
|
231
233
|
}
|
|
232
234
|
|
|
235
|
+
const ContextService = diScoped.scoped(class {
|
|
236
|
+
constructor(context) {
|
|
237
|
+
this.context = context;
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const GET_RAW_CANDLES_FN = async (self, symbol, interval, limit, sDate, eDate) => {
|
|
242
|
+
if (ContextService.hasContext()) {
|
|
243
|
+
return await backtestKit.Exchange.getRawCandles(symbol, interval, self.contextService.context, limit, sDate, eDate);
|
|
244
|
+
}
|
|
245
|
+
if (!backtestKit.MethodContextService.hasContext()) {
|
|
246
|
+
throw new Error("MethodContextService context is required to get market data for pinets if exchangeName?: string is not specified");
|
|
247
|
+
}
|
|
248
|
+
if (!backtestKit.ExecutionContextService.hasContext()) {
|
|
249
|
+
throw new Error("ExecutionContextService context is required to get market data for pinets if exchangeName?: string is not specified");
|
|
250
|
+
}
|
|
251
|
+
return await backtestKit.getRawCandles(symbol, interval, limit, sDate, eDate);
|
|
252
|
+
};
|
|
233
253
|
class CandleProviderService {
|
|
234
254
|
constructor() {
|
|
235
255
|
this.loggerService = inject(TYPES.loggerService);
|
|
256
|
+
this.contextService = inject(TYPES.contextService);
|
|
236
257
|
}
|
|
237
258
|
async getMarketData(tickerId, timeframe, limit, sDate, eDate) {
|
|
238
259
|
this.loggerService.log("candleProviderService getMarketData", {
|
|
@@ -245,7 +266,7 @@ class CandleProviderService {
|
|
|
245
266
|
const symbol = tickerId
|
|
246
267
|
.toUpperCase()
|
|
247
268
|
.replace(/^BINANCE:|^BYBIT:|^OKX:/, "");
|
|
248
|
-
const rawCandles = await
|
|
269
|
+
const rawCandles = await GET_RAW_CANDLES_FN(this, symbol, timeframe, limit, sDate, eDate);
|
|
249
270
|
const candles = rawCandles.map((c) => ({
|
|
250
271
|
openTime: c.timestamp,
|
|
251
272
|
open: c.open,
|
|
@@ -553,6 +574,7 @@ class PineMarkdownService {
|
|
|
553
574
|
|
|
554
575
|
{
|
|
555
576
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
577
|
+
provide(TYPES.contextService, () => new ContextService());
|
|
556
578
|
}
|
|
557
579
|
{
|
|
558
580
|
provide(TYPES.axisProviderService, () => new AxisProviderService());
|
|
@@ -576,6 +598,7 @@ class PineMarkdownService {
|
|
|
576
598
|
|
|
577
599
|
const commonServices = {
|
|
578
600
|
loggerService: inject(TYPES.loggerService),
|
|
601
|
+
contextService: inject(TYPES.contextService),
|
|
579
602
|
};
|
|
580
603
|
const providerServices = {
|
|
581
604
|
axisProviderService: inject(TYPES.axisProviderService),
|
|
@@ -626,7 +649,13 @@ const GET_SOURCE_FN$1 = async (source) => {
|
|
|
626
649
|
}
|
|
627
650
|
throw new Error("Source must be a File or Code instance");
|
|
628
651
|
};
|
|
629
|
-
async
|
|
652
|
+
const RUN_INFERENCE_FN = async (script, symbol, timeframe, limit, exchangeName) => {
|
|
653
|
+
if (exchangeName) {
|
|
654
|
+
return await ContextService.runInContext(async () => await pine.pineJobService.run(script, symbol, timeframe, limit), { exchangeName });
|
|
655
|
+
}
|
|
656
|
+
return await pine.pineJobService.run(script, symbol, timeframe, limit);
|
|
657
|
+
};
|
|
658
|
+
async function run(source, { symbol, timeframe, limit }, exchangeName) {
|
|
630
659
|
pine.loggerService.info(METHOD_NAME_RUN$2, {
|
|
631
660
|
source,
|
|
632
661
|
symbol,
|
|
@@ -634,7 +663,7 @@ async function run(source, { symbol, timeframe, limit }) {
|
|
|
634
663
|
limit,
|
|
635
664
|
});
|
|
636
665
|
const script = await GET_SOURCE_FN$1(source);
|
|
637
|
-
const { plots } = await
|
|
666
|
+
const { plots } = await RUN_INFERENCE_FN(script, symbol, timeframe, limit, exchangeName);
|
|
638
667
|
return plots;
|
|
639
668
|
}
|
|
640
669
|
|
|
@@ -726,6 +755,16 @@ async function dumpPlotData(signalId, plots, mapping, taName, outputDir = "./dum
|
|
|
726
755
|
return await pine.pineMarkdownService.dump(signalId, plots, mapping, taName, outputDir);
|
|
727
756
|
}
|
|
728
757
|
|
|
758
|
+
const TO_MARKDOWN_METHOD_NAME = "markdown.toMarkdown";
|
|
759
|
+
async function toMarkdown(signalId, plots, mapping) {
|
|
760
|
+
pine.loggerService.log(TO_MARKDOWN_METHOD_NAME, {
|
|
761
|
+
signalId,
|
|
762
|
+
plotCount: Object.keys(plots).length,
|
|
763
|
+
mapping,
|
|
764
|
+
});
|
|
765
|
+
return await pine.pineMarkdownService.getReport(signalId, plots, mapping);
|
|
766
|
+
}
|
|
767
|
+
|
|
729
768
|
exports.AXIS_SYMBOL = AXIS_SYMBOL;
|
|
730
769
|
exports.Code = Code;
|
|
731
770
|
exports.File = File;
|
|
@@ -735,5 +774,6 @@ exports.getSignal = getSignal;
|
|
|
735
774
|
exports.lib = pine;
|
|
736
775
|
exports.run = run;
|
|
737
776
|
exports.setLogger = setLogger;
|
|
777
|
+
exports.toMarkdown = toMarkdown;
|
|
738
778
|
exports.toSignalDto = toSignalDto;
|
|
739
779
|
exports.usePine = usePine;
|
package/build/index.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { join } from 'path';
|
|
2
|
-
import { getDate,
|
|
2
|
+
import { getDate, Exchange, MethodContextService, ExecutionContextService, getRawCandles, Markdown, lib } from 'backtest-kit';
|
|
3
3
|
import { createActivator } from 'di-kit';
|
|
4
|
+
import { scoped } from 'di-scoped';
|
|
4
5
|
import { singleshot, memoize, randomString } from 'functools-kit';
|
|
5
6
|
import fs from 'fs/promises';
|
|
6
7
|
import { createRequire } from 'module';
|
|
@@ -79,6 +80,7 @@ const { provide, inject, init, override } = createActivator("pine");
|
|
|
79
80
|
|
|
80
81
|
const baseServices = {
|
|
81
82
|
loggerService: Symbol("loggerService"),
|
|
83
|
+
contextService: Symbol("contextService"),
|
|
82
84
|
};
|
|
83
85
|
const providerServices$1 = {
|
|
84
86
|
axisProviderService: Symbol("axisProviderService"),
|
|
@@ -227,9 +229,28 @@ class AxisProviderService {
|
|
|
227
229
|
}
|
|
228
230
|
}
|
|
229
231
|
|
|
232
|
+
const ContextService = scoped(class {
|
|
233
|
+
constructor(context) {
|
|
234
|
+
this.context = context;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
const GET_RAW_CANDLES_FN = async (self, symbol, interval, limit, sDate, eDate) => {
|
|
239
|
+
if (ContextService.hasContext()) {
|
|
240
|
+
return await Exchange.getRawCandles(symbol, interval, self.contextService.context, limit, sDate, eDate);
|
|
241
|
+
}
|
|
242
|
+
if (!MethodContextService.hasContext()) {
|
|
243
|
+
throw new Error("MethodContextService context is required to get market data for pinets if exchangeName?: string is not specified");
|
|
244
|
+
}
|
|
245
|
+
if (!ExecutionContextService.hasContext()) {
|
|
246
|
+
throw new Error("ExecutionContextService context is required to get market data for pinets if exchangeName?: string is not specified");
|
|
247
|
+
}
|
|
248
|
+
return await getRawCandles(symbol, interval, limit, sDate, eDate);
|
|
249
|
+
};
|
|
230
250
|
class CandleProviderService {
|
|
231
251
|
constructor() {
|
|
232
252
|
this.loggerService = inject(TYPES.loggerService);
|
|
253
|
+
this.contextService = inject(TYPES.contextService);
|
|
233
254
|
}
|
|
234
255
|
async getMarketData(tickerId, timeframe, limit, sDate, eDate) {
|
|
235
256
|
this.loggerService.log("candleProviderService getMarketData", {
|
|
@@ -242,7 +263,7 @@ class CandleProviderService {
|
|
|
242
263
|
const symbol = tickerId
|
|
243
264
|
.toUpperCase()
|
|
244
265
|
.replace(/^BINANCE:|^BYBIT:|^OKX:/, "");
|
|
245
|
-
const rawCandles = await
|
|
266
|
+
const rawCandles = await GET_RAW_CANDLES_FN(this, symbol, timeframe, limit, sDate, eDate);
|
|
246
267
|
const candles = rawCandles.map((c) => ({
|
|
247
268
|
openTime: c.timestamp,
|
|
248
269
|
open: c.open,
|
|
@@ -550,6 +571,7 @@ class PineMarkdownService {
|
|
|
550
571
|
|
|
551
572
|
{
|
|
552
573
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
574
|
+
provide(TYPES.contextService, () => new ContextService());
|
|
553
575
|
}
|
|
554
576
|
{
|
|
555
577
|
provide(TYPES.axisProviderService, () => new AxisProviderService());
|
|
@@ -573,6 +595,7 @@ class PineMarkdownService {
|
|
|
573
595
|
|
|
574
596
|
const commonServices = {
|
|
575
597
|
loggerService: inject(TYPES.loggerService),
|
|
598
|
+
contextService: inject(TYPES.contextService),
|
|
576
599
|
};
|
|
577
600
|
const providerServices = {
|
|
578
601
|
axisProviderService: inject(TYPES.axisProviderService),
|
|
@@ -623,7 +646,13 @@ const GET_SOURCE_FN$1 = async (source) => {
|
|
|
623
646
|
}
|
|
624
647
|
throw new Error("Source must be a File or Code instance");
|
|
625
648
|
};
|
|
626
|
-
async
|
|
649
|
+
const RUN_INFERENCE_FN = async (script, symbol, timeframe, limit, exchangeName) => {
|
|
650
|
+
if (exchangeName) {
|
|
651
|
+
return await ContextService.runInContext(async () => await pine.pineJobService.run(script, symbol, timeframe, limit), { exchangeName });
|
|
652
|
+
}
|
|
653
|
+
return await pine.pineJobService.run(script, symbol, timeframe, limit);
|
|
654
|
+
};
|
|
655
|
+
async function run(source, { symbol, timeframe, limit }, exchangeName) {
|
|
627
656
|
pine.loggerService.info(METHOD_NAME_RUN$2, {
|
|
628
657
|
source,
|
|
629
658
|
symbol,
|
|
@@ -631,7 +660,7 @@ async function run(source, { symbol, timeframe, limit }) {
|
|
|
631
660
|
limit,
|
|
632
661
|
});
|
|
633
662
|
const script = await GET_SOURCE_FN$1(source);
|
|
634
|
-
const { plots } = await
|
|
663
|
+
const { plots } = await RUN_INFERENCE_FN(script, symbol, timeframe, limit, exchangeName);
|
|
635
664
|
return plots;
|
|
636
665
|
}
|
|
637
666
|
|
|
@@ -723,4 +752,14 @@ async function dumpPlotData(signalId, plots, mapping, taName, outputDir = "./dum
|
|
|
723
752
|
return await pine.pineMarkdownService.dump(signalId, plots, mapping, taName, outputDir);
|
|
724
753
|
}
|
|
725
754
|
|
|
726
|
-
|
|
755
|
+
const TO_MARKDOWN_METHOD_NAME = "markdown.toMarkdown";
|
|
756
|
+
async function toMarkdown(signalId, plots, mapping) {
|
|
757
|
+
pine.loggerService.log(TO_MARKDOWN_METHOD_NAME, {
|
|
758
|
+
signalId,
|
|
759
|
+
plotCount: Object.keys(plots).length,
|
|
760
|
+
mapping,
|
|
761
|
+
});
|
|
762
|
+
return await pine.pineMarkdownService.getReport(signalId, plots, mapping);
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
export { AXIS_SYMBOL, Code, File, dumpPlotData, extract, getSignal, pine as lib, run, setLogger, toMarkdown, toSignalDto, usePine };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backtest-kit/pinets",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.3",
|
|
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,12 +42,17 @@ interface IPine {
|
|
|
42
42
|
|
|
43
43
|
declare function usePine<T = TPineCtor>(ctor: T): void;
|
|
44
44
|
|
|
45
|
+
type ExchangeName = string;
|
|
46
|
+
interface IContext {
|
|
47
|
+
exchangeName: ExchangeName;
|
|
48
|
+
}
|
|
49
|
+
|
|
45
50
|
interface IRunParams {
|
|
46
51
|
symbol: string;
|
|
47
52
|
timeframe: CandleInterval;
|
|
48
53
|
limit: number;
|
|
49
54
|
}
|
|
50
|
-
declare function run(source: File | Code, { symbol, timeframe, limit }: IRunParams): Promise<PlotModel>;
|
|
55
|
+
declare function run(source: File | Code, { symbol, timeframe, limit }: IRunParams, exchangeName?: ExchangeName): Promise<PlotModel>;
|
|
51
56
|
|
|
52
57
|
type PlotExtractConfig<T = number> = {
|
|
53
58
|
plot: string;
|
|
@@ -83,8 +88,11 @@ interface IParams {
|
|
|
83
88
|
}
|
|
84
89
|
declare function getSignal(source: File | Code, { symbol, timeframe, limit }: IParams): Promise<ISignalDto | null>;
|
|
85
90
|
|
|
91
|
+
type ResultId$3 = string | number;
|
|
92
|
+
declare function dumpPlotData<M extends PlotMapping>(signalId: ResultId$3, plots: PlotModel, mapping: M, taName: string, outputDir?: string): Promise<void>;
|
|
93
|
+
|
|
86
94
|
type ResultId$2 = string | number;
|
|
87
|
-
declare function
|
|
95
|
+
declare function toMarkdown<M extends PlotMapping>(signalId: ResultId$2, plots: PlotModel, mapping: M): Promise<string>;
|
|
88
96
|
|
|
89
97
|
type ResultId$1 = string | number;
|
|
90
98
|
interface SignalData {
|
|
@@ -135,7 +143,10 @@ declare class LoggerService implements ILogger {
|
|
|
135
143
|
}
|
|
136
144
|
|
|
137
145
|
declare class CandleProviderService implements IProvider {
|
|
138
|
-
|
|
146
|
+
readonly loggerService: LoggerService;
|
|
147
|
+
readonly contextService: {
|
|
148
|
+
readonly context: IContext;
|
|
149
|
+
};
|
|
139
150
|
getMarketData(tickerId: string, timeframe: string, limit?: number, sDate?: number, eDate?: number): Promise<any[]>;
|
|
140
151
|
getSymbolInfo(tickerId: string): Promise<any>;
|
|
141
152
|
}
|
|
@@ -183,6 +194,9 @@ declare const pine: {
|
|
|
183
194
|
axisProviderService: AxisProviderService;
|
|
184
195
|
candleProviderService: CandleProviderService;
|
|
185
196
|
loggerService: LoggerService;
|
|
197
|
+
contextService: {
|
|
198
|
+
readonly context: IContext;
|
|
199
|
+
};
|
|
186
200
|
};
|
|
187
201
|
|
|
188
|
-
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, toSignalDto, usePine };
|
|
202
|
+
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, toMarkdown, toSignalDto, usePine };
|