@backtest-kit/cli 3.3.4 → 3.3.6
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 +156 -69
- package/build/index.mjs +110 -23
- package/package.json +8 -5
- package/types.d.ts +26 -1
package/build/index.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var BacktestKit = require('backtest-kit');
|
|
5
5
|
var functoolsKit = require('functools-kit');
|
|
6
6
|
var fs = require('fs');
|
|
7
7
|
var stackTrace = require('stack-trace');
|
|
@@ -23,6 +23,8 @@ var MarkdownIt = require('markdown-it');
|
|
|
23
23
|
var sanitizeHtml = require('sanitize-html');
|
|
24
24
|
var jsdom = require('jsdom');
|
|
25
25
|
var Mustache = require('mustache');
|
|
26
|
+
var standalone = require('@babel/standalone');
|
|
27
|
+
var pluginUMD = require('@babel/plugin-transform-modules-umd');
|
|
26
28
|
|
|
27
29
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
28
30
|
function _interopNamespaceDefault(e) {
|
|
@@ -42,6 +44,7 @@ function _interopNamespaceDefault(e) {
|
|
|
42
44
|
return Object.freeze(n);
|
|
43
45
|
}
|
|
44
46
|
|
|
47
|
+
var BacktestKit__namespace = /*#__PURE__*/_interopNamespaceDefault(BacktestKit);
|
|
45
48
|
var stackTrace__namespace = /*#__PURE__*/_interopNamespaceDefault(stackTrace);
|
|
46
49
|
|
|
47
50
|
/**
|
|
@@ -75,22 +78,22 @@ var stackTrace__namespace = /*#__PURE__*/_interopNamespaceDefault(stackTrace);
|
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
{
|
|
78
|
-
|
|
79
|
-
|
|
81
|
+
BacktestKit.Storage.enable();
|
|
82
|
+
BacktestKit.Notification.enable();
|
|
80
83
|
}
|
|
81
84
|
{
|
|
82
|
-
|
|
83
|
-
|
|
85
|
+
BacktestKit.Markdown.disable();
|
|
86
|
+
BacktestKit.Report.enable();
|
|
84
87
|
}
|
|
85
88
|
{
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
BacktestKit.StorageLive.usePersist();
|
|
90
|
+
BacktestKit.StorageBacktest.useMemory();
|
|
88
91
|
}
|
|
89
92
|
{
|
|
90
|
-
|
|
91
|
-
|
|
93
|
+
BacktestKit.NotificationLive.usePersist();
|
|
94
|
+
BacktestKit.NotificationBacktest.useMemory();
|
|
92
95
|
}
|
|
93
|
-
|
|
96
|
+
BacktestKit.setConfig({
|
|
94
97
|
CC_MAX_NOTIFICATIONS: 5000,
|
|
95
98
|
CC_MAX_SIGNALS: 750,
|
|
96
99
|
});
|
|
@@ -191,6 +194,7 @@ const baseServices$1 = {
|
|
|
191
194
|
errorService: Symbol('errorService'),
|
|
192
195
|
loggerService: Symbol('loggerService'),
|
|
193
196
|
resolveService: Symbol('resolveService'),
|
|
197
|
+
babelService: Symbol('babelService'),
|
|
194
198
|
};
|
|
195
199
|
const connectionServices$1 = {
|
|
196
200
|
moduleConnectionService: Symbol('moduleConnectionService'),
|
|
@@ -234,12 +238,12 @@ const TYPES = {
|
|
|
234
238
|
|
|
235
239
|
const entrySubject = new functoolsKit.BehaviorSubject();
|
|
236
240
|
|
|
237
|
-
const __filename$
|
|
238
|
-
const __dirname$
|
|
239
|
-
const require$
|
|
241
|
+
const __filename$2 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
242
|
+
const __dirname$2 = path.dirname(__filename$2);
|
|
243
|
+
const require$3 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
240
244
|
const REQUIRE_ENTRY_FACTORY = (filePath) => {
|
|
241
245
|
try {
|
|
242
|
-
require$
|
|
246
|
+
require$3(filePath);
|
|
243
247
|
return true;
|
|
244
248
|
}
|
|
245
249
|
catch {
|
|
@@ -247,26 +251,39 @@ const REQUIRE_ENTRY_FACTORY = (filePath) => {
|
|
|
247
251
|
}
|
|
248
252
|
};
|
|
249
253
|
const IMPORT_ENTRY_FACTORY = async (filePath) => {
|
|
250
|
-
|
|
254
|
+
{
|
|
255
|
+
return false;
|
|
256
|
+
}
|
|
251
257
|
};
|
|
252
|
-
const
|
|
253
|
-
const
|
|
254
|
-
|
|
258
|
+
const BABEL_ENTRY_FACTORY = async (filePath, self) => {
|
|
259
|
+
const code = await fs$1.readFile(filePath, "utf-8");
|
|
260
|
+
try {
|
|
261
|
+
await self.babelService.transpileAndRun(code);
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
catch (error) {
|
|
265
|
+
console.log(functoolsKit.getErrorMessage(error));
|
|
266
|
+
return false;
|
|
267
|
+
}
|
|
255
268
|
};
|
|
256
|
-
const LOAD_ENTRY_FN = async (filePath) => {
|
|
257
|
-
if (
|
|
258
|
-
await TSX_ENTRY_FACTORY(filePath);
|
|
269
|
+
const LOAD_ENTRY_FN = async (filePath, self) => {
|
|
270
|
+
if (REQUIRE_ENTRY_FACTORY(filePath)) {
|
|
259
271
|
return;
|
|
260
272
|
}
|
|
261
|
-
if (
|
|
262
|
-
|
|
273
|
+
if (await IMPORT_ENTRY_FACTORY()) {
|
|
274
|
+
return;
|
|
263
275
|
}
|
|
276
|
+
if (await BABEL_ENTRY_FACTORY(filePath, self)) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
throw new Error(`Failed to load entry point: ${filePath}`);
|
|
264
280
|
};
|
|
265
281
|
let _is_launched = false;
|
|
266
282
|
class ResolveService {
|
|
267
283
|
constructor() {
|
|
268
284
|
this.loggerService = inject(TYPES.loggerService);
|
|
269
|
-
this.
|
|
285
|
+
this.babelService = inject(TYPES.babelService);
|
|
286
|
+
this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname$2, '..', 'template');
|
|
270
287
|
this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
|
|
271
288
|
this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
|
|
272
289
|
this.attachEntryPoint = async (entryPoint) => {
|
|
@@ -282,7 +299,7 @@ class ResolveService {
|
|
|
282
299
|
process.chdir(moduleRoot);
|
|
283
300
|
dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
|
|
284
301
|
dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
|
|
285
|
-
await LOAD_ENTRY_FN(absolutePath);
|
|
302
|
+
await LOAD_ENTRY_FN(absolutePath, this);
|
|
286
303
|
await entrySubject.next(absolutePath);
|
|
287
304
|
}
|
|
288
305
|
_is_launched = true;
|
|
@@ -312,7 +329,7 @@ var ExchangeName$1 = ExchangeName;
|
|
|
312
329
|
const ADD_EXCHANGE_FN = (self) => {
|
|
313
330
|
self.loggerService.log("Adding CCXT Binance as a default exchange schema");
|
|
314
331
|
console.warn("Warning: The default exchange schema is set to CCXT Binance. Please make sure to update it according to your needs using --exchange cli param.");
|
|
315
|
-
|
|
332
|
+
BacktestKit.addExchangeSchema({
|
|
316
333
|
exchangeName: ExchangeName$1.DefaultExchange,
|
|
317
334
|
getCandles: async (symbol, interval, since, limit) => {
|
|
318
335
|
const exchange = await getExchange();
|
|
@@ -331,7 +348,7 @@ const ADD_EXCHANGE_FN = (self) => {
|
|
|
331
348
|
const market = exchange.market(symbol);
|
|
332
349
|
const tickSize = market.limits?.price?.min || market.precision?.price;
|
|
333
350
|
if (tickSize !== undefined) {
|
|
334
|
-
return
|
|
351
|
+
return BacktestKit.roundTicks(price, tickSize);
|
|
335
352
|
}
|
|
336
353
|
return exchange.priceToPrecision(symbol, price);
|
|
337
354
|
},
|
|
@@ -340,7 +357,7 @@ const ADD_EXCHANGE_FN = (self) => {
|
|
|
340
357
|
const market = exchange.market(symbol);
|
|
341
358
|
const stepSize = market.limits?.amount?.min || market.precision?.amount;
|
|
342
359
|
if (stepSize !== undefined) {
|
|
343
|
-
return
|
|
360
|
+
return BacktestKit.roundTicks(quantity, stepSize);
|
|
344
361
|
}
|
|
345
362
|
return exchange.amountToPrecision(symbol, quantity);
|
|
346
363
|
},
|
|
@@ -369,7 +386,7 @@ class ExchangeSchemaService {
|
|
|
369
386
|
this.loggerService = inject(TYPES.loggerService);
|
|
370
387
|
this.addSchema = functoolsKit.singleshot(async () => {
|
|
371
388
|
this.loggerService.log("exchangeSchemaService addSchema");
|
|
372
|
-
const { length } = await
|
|
389
|
+
const { length } = await BacktestKit.listExchangeSchema();
|
|
373
390
|
!length && ADD_EXCHANGE_FN(this);
|
|
374
391
|
});
|
|
375
392
|
}
|
|
@@ -446,7 +463,7 @@ const getArgs = functoolsKit.singleshot(() => {
|
|
|
446
463
|
const ADD_FRAME_FN = (self) => {
|
|
447
464
|
self.loggerService.log("Adding February 2024 as a default frame schema");
|
|
448
465
|
console.warn("Warning: The default frame schema is set to February 2024. Please make sure to update it according to your needs using --frame cli param.");
|
|
449
|
-
|
|
466
|
+
BacktestKit.addFrameSchema({
|
|
450
467
|
frameName: FrameName$1.DefaultFrame,
|
|
451
468
|
interval: "1m",
|
|
452
469
|
startDate: new Date("2024-02-01T00:00:00Z"),
|
|
@@ -461,7 +478,7 @@ class FrameSchemaService {
|
|
|
461
478
|
if (!getArgs().values.backtest) {
|
|
462
479
|
return;
|
|
463
480
|
}
|
|
464
|
-
const { length } = await
|
|
481
|
+
const { length } = await BacktestKit.listFrameSchema();
|
|
465
482
|
!length && ADD_FRAME_FN(this);
|
|
466
483
|
});
|
|
467
484
|
}
|
|
@@ -481,11 +498,11 @@ class SymbolSchemaService {
|
|
|
481
498
|
|
|
482
499
|
const notifyFinish = functoolsKit.singleshot(() => {
|
|
483
500
|
let disposeRef;
|
|
484
|
-
const unLive =
|
|
501
|
+
const unLive = BacktestKit.listenDoneLive(() => {
|
|
485
502
|
console.log("Live trading finished");
|
|
486
503
|
disposeRef && disposeRef();
|
|
487
504
|
});
|
|
488
|
-
const unBacktest =
|
|
505
|
+
const unBacktest = BacktestKit.listenDoneBacktest(() => {
|
|
489
506
|
console.log("Backtest trading finished");
|
|
490
507
|
disposeRef && disposeRef();
|
|
491
508
|
});
|
|
@@ -499,7 +516,7 @@ const getEntry = (metaUrl) => {
|
|
|
499
516
|
|
|
500
517
|
const notifyVerbose = functoolsKit.singleshot(() => {
|
|
501
518
|
console.log("Using verbose logging...");
|
|
502
|
-
|
|
519
|
+
BacktestKit.listenSignal((event) => {
|
|
503
520
|
if (event.action === "scheduled") {
|
|
504
521
|
console.log(`[POSITION SCHEDULED] ${event.symbol}`);
|
|
505
522
|
console.log(` Strategy: ${event.strategyName}`);
|
|
@@ -579,9 +596,9 @@ class BacktestMainService {
|
|
|
579
596
|
this.frameSchemaService.addSchema();
|
|
580
597
|
}
|
|
581
598
|
const symbol = payload.symbol || "BTCUSDT";
|
|
582
|
-
const [defaultStrategyName = null] = await
|
|
583
|
-
const [defaultExchangeName = null] = await
|
|
584
|
-
const [defaultFrameName = null] = await
|
|
599
|
+
const [defaultStrategyName = null] = await BacktestKit.listStrategySchema();
|
|
600
|
+
const [defaultExchangeName = null] = await BacktestKit.listExchangeSchema();
|
|
601
|
+
const [defaultFrameName = null] = await BacktestKit.listFrameSchema();
|
|
585
602
|
const strategyName = payload.strategy || defaultStrategyName?.strategyName;
|
|
586
603
|
if (!strategyName) {
|
|
587
604
|
throw new Error("Strategy name is required");
|
|
@@ -602,7 +619,7 @@ class BacktestMainService {
|
|
|
602
619
|
});
|
|
603
620
|
}
|
|
604
621
|
if (payload.verbose) {
|
|
605
|
-
|
|
622
|
+
BacktestKit.overrideExchangeSchema({
|
|
606
623
|
exchangeName,
|
|
607
624
|
callbacks: {
|
|
608
625
|
onCandleData(symbol, interval, since) {
|
|
@@ -612,7 +629,7 @@ class BacktestMainService {
|
|
|
612
629
|
});
|
|
613
630
|
notifyVerbose();
|
|
614
631
|
}
|
|
615
|
-
|
|
632
|
+
BacktestKit.Backtest.background(symbol, {
|
|
616
633
|
strategyName,
|
|
617
634
|
frameName,
|
|
618
635
|
exchangeName,
|
|
@@ -671,8 +688,8 @@ class LiveMainService {
|
|
|
671
688
|
this.symbolSchemaService.addSchema();
|
|
672
689
|
}
|
|
673
690
|
const symbol = payload.symbol || "BTCUSDT";
|
|
674
|
-
const [defaultStrategyName = null] = await
|
|
675
|
-
const [defaultExchangeName = null] = await
|
|
691
|
+
const [defaultStrategyName = null] = await BacktestKit.listStrategySchema();
|
|
692
|
+
const [defaultExchangeName = null] = await BacktestKit.listExchangeSchema();
|
|
676
693
|
const strategyName = payload.strategy || defaultStrategyName?.strategyName;
|
|
677
694
|
if (!strategyName) {
|
|
678
695
|
throw new Error("Strategy name is required");
|
|
@@ -682,7 +699,7 @@ class LiveMainService {
|
|
|
682
699
|
throw new Error("Exchange name is required");
|
|
683
700
|
}
|
|
684
701
|
if (payload.verbose) {
|
|
685
|
-
|
|
702
|
+
BacktestKit.overrideExchangeSchema({
|
|
686
703
|
exchangeName,
|
|
687
704
|
callbacks: {
|
|
688
705
|
onCandleData(symbol, interval, since) {
|
|
@@ -692,7 +709,7 @@ class LiveMainService {
|
|
|
692
709
|
});
|
|
693
710
|
notifyVerbose();
|
|
694
711
|
}
|
|
695
|
-
|
|
712
|
+
BacktestKit.Live.background(symbol, {
|
|
696
713
|
strategyName,
|
|
697
714
|
exchangeName,
|
|
698
715
|
});
|
|
@@ -742,8 +759,8 @@ class PaperMainService {
|
|
|
742
759
|
this.symbolSchemaService.addSchema();
|
|
743
760
|
}
|
|
744
761
|
const symbol = payload.symbol || "BTCUSDT";
|
|
745
|
-
const [defaultStrategyName = null] = await
|
|
746
|
-
const [defaultExchangeName = null] = await
|
|
762
|
+
const [defaultStrategyName = null] = await BacktestKit.listStrategySchema();
|
|
763
|
+
const [defaultExchangeName = null] = await BacktestKit.listExchangeSchema();
|
|
747
764
|
const strategyName = payload.strategy || defaultStrategyName?.strategyName;
|
|
748
765
|
if (!strategyName) {
|
|
749
766
|
throw new Error("Strategy name is required");
|
|
@@ -753,7 +770,7 @@ class PaperMainService {
|
|
|
753
770
|
throw new Error("Exchange name is required");
|
|
754
771
|
}
|
|
755
772
|
if (payload.verbose) {
|
|
756
|
-
|
|
773
|
+
BacktestKit.overrideExchangeSchema({
|
|
757
774
|
exchangeName,
|
|
758
775
|
callbacks: {
|
|
759
776
|
onCandleData(symbol, interval, since) {
|
|
@@ -763,7 +780,7 @@ class PaperMainService {
|
|
|
763
780
|
});
|
|
764
781
|
notifyVerbose();
|
|
765
782
|
}
|
|
766
|
-
|
|
783
|
+
BacktestKit.Live.background(symbol, {
|
|
767
784
|
strategyName,
|
|
768
785
|
exchangeName,
|
|
769
786
|
});
|
|
@@ -873,7 +890,7 @@ class TelegramProviderService {
|
|
|
873
890
|
|
|
874
891
|
const CANDLES_LIMIT = 160;
|
|
875
892
|
const GET_CONFIG_FN = async (symbol, interval) => {
|
|
876
|
-
const candles = await
|
|
893
|
+
const candles = await BacktestKit.getCandles(symbol, interval, CANDLES_LIMIT);
|
|
877
894
|
const labels = candles.map(({ timestamp }) => new Date(timestamp).toLocaleTimeString("en-US", {
|
|
878
895
|
hour: "2-digit",
|
|
879
896
|
minute: "2-digit",
|
|
@@ -1289,7 +1306,7 @@ class TelegramWebService {
|
|
|
1289
1306
|
}
|
|
1290
1307
|
|
|
1291
1308
|
const GET_TIMEFRAME_RANGE_FN = async (frameName) => {
|
|
1292
|
-
const frameList = await
|
|
1309
|
+
const frameList = await BacktestKit.listFrameSchema();
|
|
1293
1310
|
const frameSchema = frameList.find((frameSchema) => frameSchema.frameName === frameName);
|
|
1294
1311
|
if (!frameSchema) {
|
|
1295
1312
|
throw new Error(`Frame with name ${frameName} not found`);
|
|
@@ -1300,7 +1317,7 @@ const GET_TIMEFRAME_RANGE_FN = async (frameName) => {
|
|
|
1300
1317
|
const CACHE_CANDLES_FN = functoolsKit.retry(async (interval, dto) => {
|
|
1301
1318
|
try {
|
|
1302
1319
|
console.log(`Checking candles cache for ${dto.symbol} ${interval} from ${dto.from} to ${dto.to}`);
|
|
1303
|
-
await
|
|
1320
|
+
await BacktestKit.checkCandles({
|
|
1304
1321
|
exchangeName: dto.exchangeName,
|
|
1305
1322
|
from: dto.from,
|
|
1306
1323
|
to: dto.to,
|
|
@@ -1310,7 +1327,7 @@ const CACHE_CANDLES_FN = functoolsKit.retry(async (interval, dto) => {
|
|
|
1310
1327
|
}
|
|
1311
1328
|
catch (error) {
|
|
1312
1329
|
console.log(`Caching candles for ${dto.symbol} ${interval} from ${dto.from} to ${dto.to}`);
|
|
1313
|
-
await
|
|
1330
|
+
await BacktestKit.warmCandles({
|
|
1314
1331
|
symbol: dto.symbol,
|
|
1315
1332
|
exchangeName: dto.exchangeName,
|
|
1316
1333
|
from: dto.from,
|
|
@@ -1467,10 +1484,10 @@ class TelegramLogicService {
|
|
|
1467
1484
|
};
|
|
1468
1485
|
this.connect = functoolsKit.singleshot(() => {
|
|
1469
1486
|
this.loggerService.log("telegramLogicService connect");
|
|
1470
|
-
const unRisk =
|
|
1487
|
+
const unRisk = BacktestKit.listenRisk(async (event) => {
|
|
1471
1488
|
await this.notifyRisk(event);
|
|
1472
1489
|
});
|
|
1473
|
-
const unSignal =
|
|
1490
|
+
const unSignal = BacktestKit.listenSignal(async (event) => {
|
|
1474
1491
|
if (event.action === "scheduled") {
|
|
1475
1492
|
await this.notifyScheduled(event);
|
|
1476
1493
|
return;
|
|
@@ -1488,7 +1505,7 @@ class TelegramLogicService {
|
|
|
1488
1505
|
return;
|
|
1489
1506
|
}
|
|
1490
1507
|
});
|
|
1491
|
-
const unCommit =
|
|
1508
|
+
const unCommit = BacktestKit.listenStrategyCommit(async (event) => {
|
|
1492
1509
|
if (event.action === "trailing-take") {
|
|
1493
1510
|
await this.notifyTrailingTake(event);
|
|
1494
1511
|
return;
|
|
@@ -1613,7 +1630,7 @@ class TelegramTemplateService {
|
|
|
1613
1630
|
}
|
|
1614
1631
|
}
|
|
1615
1632
|
|
|
1616
|
-
const require$
|
|
1633
|
+
const require$2 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
1617
1634
|
const getExtVariants = (fileName) => {
|
|
1618
1635
|
const ext = path.extname(fileName);
|
|
1619
1636
|
const base = ext ? fileName.slice(0, -ext.length) : fileName;
|
|
@@ -1622,7 +1639,7 @@ const getExtVariants = (fileName) => {
|
|
|
1622
1639
|
const REQUIRE_MODULE_FACTORY = (fileName) => {
|
|
1623
1640
|
for (const variant of getExtVariants(fileName)) {
|
|
1624
1641
|
try {
|
|
1625
|
-
return require$
|
|
1642
|
+
return require$2(variant);
|
|
1626
1643
|
}
|
|
1627
1644
|
catch {
|
|
1628
1645
|
continue;
|
|
@@ -1631,11 +1648,19 @@ const REQUIRE_MODULE_FACTORY = (fileName) => {
|
|
|
1631
1648
|
return null;
|
|
1632
1649
|
};
|
|
1633
1650
|
const IMPORT_MODULE_FACTORY = async (fileName) => {
|
|
1651
|
+
{
|
|
1652
|
+
return null;
|
|
1653
|
+
}
|
|
1654
|
+
};
|
|
1655
|
+
const BABEL_MODULE_FACTORY = async (fileName, self) => {
|
|
1634
1656
|
for (const variant of getExtVariants(fileName)) {
|
|
1635
1657
|
try {
|
|
1636
|
-
|
|
1658
|
+
const code = await fs$1.readFile(variant, "utf-8");
|
|
1659
|
+
const { exports } = self.babelService.transpileAndRun(code);
|
|
1660
|
+
return exports.default ?? exports;
|
|
1637
1661
|
}
|
|
1638
|
-
catch {
|
|
1662
|
+
catch (error) {
|
|
1663
|
+
console.log(functoolsKit.getErrorMessage(error));
|
|
1639
1664
|
continue;
|
|
1640
1665
|
}
|
|
1641
1666
|
}
|
|
@@ -1653,7 +1678,10 @@ const LOAD_MODULE_MODULE_FN = async (fileName, self) => {
|
|
|
1653
1678
|
if ((Ctor = REQUIRE_MODULE_FACTORY(resolvedFile))) {
|
|
1654
1679
|
return typeof Ctor === "function" ? new Ctor() : Ctor;
|
|
1655
1680
|
}
|
|
1656
|
-
if ((Ctor = await IMPORT_MODULE_FACTORY(
|
|
1681
|
+
if ((Ctor = await IMPORT_MODULE_FACTORY())) {
|
|
1682
|
+
return typeof Ctor === "function" ? new Ctor() : Ctor;
|
|
1683
|
+
}
|
|
1684
|
+
if ((Ctor = await BABEL_MODULE_FACTORY(resolvedFile, self))) {
|
|
1657
1685
|
return typeof Ctor === "function" ? new Ctor() : Ctor;
|
|
1658
1686
|
}
|
|
1659
1687
|
throw new Error(`Module module import failed for file: ${resolvedFile}`);
|
|
@@ -1662,6 +1690,7 @@ class ModuleConnectionService {
|
|
|
1662
1690
|
constructor() {
|
|
1663
1691
|
this.loggerService = inject(TYPES.loggerService);
|
|
1664
1692
|
this.resolveService = inject(TYPES.resolveService);
|
|
1693
|
+
this.babelService = inject(TYPES.babelService);
|
|
1665
1694
|
this.getInstance = functoolsKit.memoize(([fileName]) => `${fileName}`, async (fileName) => {
|
|
1666
1695
|
this.loggerService.log("moduleConnectionService getInstance", {
|
|
1667
1696
|
fileName,
|
|
@@ -1788,10 +1817,10 @@ class LiveProviderService {
|
|
|
1788
1817
|
console.log("No ./modules/live.module.mjs found, live trading failed to initialize");
|
|
1789
1818
|
process.exit(-1);
|
|
1790
1819
|
});
|
|
1791
|
-
const unRisk =
|
|
1820
|
+
const unRisk = BacktestKit.listenRisk(async (event) => {
|
|
1792
1821
|
await this.handleRisk(event);
|
|
1793
1822
|
});
|
|
1794
|
-
const unSignal =
|
|
1823
|
+
const unSignal = BacktestKit.listenSignal(async (event) => {
|
|
1795
1824
|
if (event.action === "scheduled") {
|
|
1796
1825
|
await this.handleScheduled(event);
|
|
1797
1826
|
return;
|
|
@@ -1809,7 +1838,7 @@ class LiveProviderService {
|
|
|
1809
1838
|
return;
|
|
1810
1839
|
}
|
|
1811
1840
|
});
|
|
1812
|
-
const unCommit =
|
|
1841
|
+
const unCommit = BacktestKit.listenStrategyCommit(async (event) => {
|
|
1813
1842
|
if (event.action === "trailing-take") {
|
|
1814
1843
|
await this.handleTrailingTake(event);
|
|
1815
1844
|
return;
|
|
@@ -1855,6 +1884,62 @@ class LiveProviderService {
|
|
|
1855
1884
|
}
|
|
1856
1885
|
}
|
|
1857
1886
|
|
|
1887
|
+
standalone.registerPlugin("plugin-transform-modules-umd", pluginUMD);
|
|
1888
|
+
const require$1 = module$1.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
1889
|
+
const __filename$1 = url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
1890
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
1891
|
+
const BacktestKitCli = new Proxy({}, {
|
|
1892
|
+
get(_target, prop) {
|
|
1893
|
+
throw new Error(`@backtest-kit/cli is not available in this context (accessed: ${String(prop)})`);
|
|
1894
|
+
},
|
|
1895
|
+
});
|
|
1896
|
+
class BabelService {
|
|
1897
|
+
constructor() {
|
|
1898
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
1899
|
+
this.transpile = (code) => {
|
|
1900
|
+
this.loggerService.log("babelService transpile", { codeLen: code.length });
|
|
1901
|
+
const result = standalone.transform(code, {
|
|
1902
|
+
filename: "index.ts",
|
|
1903
|
+
presets: ["env", "typescript"],
|
|
1904
|
+
plugins: [
|
|
1905
|
+
[
|
|
1906
|
+
"plugin-transform-modules-umd",
|
|
1907
|
+
{
|
|
1908
|
+
globals: {
|
|
1909
|
+
"backtest-kit": "BacktestKit",
|
|
1910
|
+
"@backtest-kit/cli": "BacktestKitCli",
|
|
1911
|
+
},
|
|
1912
|
+
moduleId: "Executor",
|
|
1913
|
+
},
|
|
1914
|
+
],
|
|
1915
|
+
],
|
|
1916
|
+
parserOpts: { strictMode: false },
|
|
1917
|
+
});
|
|
1918
|
+
if (!result.code) {
|
|
1919
|
+
throw new Error("BabelService transpile failed");
|
|
1920
|
+
}
|
|
1921
|
+
return result.code;
|
|
1922
|
+
};
|
|
1923
|
+
this.transpileAndRun = (code) => {
|
|
1924
|
+
this.loggerService.log("babelService transpileAndRun", {
|
|
1925
|
+
codeLen: code.length,
|
|
1926
|
+
});
|
|
1927
|
+
const module = { exports: {} };
|
|
1928
|
+
const exports = module.exports;
|
|
1929
|
+
eval(this.transpile(code));
|
|
1930
|
+
return {
|
|
1931
|
+
require: require$1,
|
|
1932
|
+
__filename: __filename$1,
|
|
1933
|
+
__dirname: __dirname$1,
|
|
1934
|
+
exports,
|
|
1935
|
+
module,
|
|
1936
|
+
};
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1940
|
+
globalThis.BacktestKit = BacktestKit__namespace;
|
|
1941
|
+
globalThis.BacktestKitCli = BacktestKitCli;
|
|
1942
|
+
|
|
1858
1943
|
{
|
|
1859
1944
|
provide(TYPES.quickchartApiService, () => new QuickchartApiService());
|
|
1860
1945
|
provide(TYPES.telegramApiService, () => new TelegramApiService());
|
|
@@ -1863,6 +1948,7 @@ class LiveProviderService {
|
|
|
1863
1948
|
provide(TYPES.errorService, () => new ErrorService());
|
|
1864
1949
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
1865
1950
|
provide(TYPES.resolveService, () => new ResolveService());
|
|
1951
|
+
provide(TYPES.babelService, () => new BabelService());
|
|
1866
1952
|
}
|
|
1867
1953
|
{
|
|
1868
1954
|
provide(TYPES.moduleConnectionService, () => new ModuleConnectionService());
|
|
@@ -1901,6 +1987,7 @@ const baseServices = {
|
|
|
1901
1987
|
errorService: inject(TYPES.errorService),
|
|
1902
1988
|
loggerService: inject(TYPES.loggerService),
|
|
1903
1989
|
resolveService: inject(TYPES.resolveService),
|
|
1990
|
+
babelService: inject(TYPES.babelService),
|
|
1904
1991
|
};
|
|
1905
1992
|
const connectionServices = {
|
|
1906
1993
|
moduleConnectionService: inject(TYPES.moduleConnectionService),
|
|
@@ -1949,7 +2036,7 @@ const notifyShutdown = functoolsKit.singleshot(async () => {
|
|
|
1949
2036
|
|
|
1950
2037
|
const BEFORE_EXIT_FN$4 = functoolsKit.singleshot(async () => {
|
|
1951
2038
|
process.off("SIGINT", BEFORE_EXIT_FN$4);
|
|
1952
|
-
const [running = null] = await
|
|
2039
|
+
const [running = null] = await BacktestKit.Backtest.list();
|
|
1953
2040
|
if (!running) {
|
|
1954
2041
|
return;
|
|
1955
2042
|
}
|
|
@@ -1958,7 +2045,7 @@ const BEFORE_EXIT_FN$4 = functoolsKit.singleshot(async () => {
|
|
|
1958
2045
|
if (status === "fulfilled") {
|
|
1959
2046
|
return;
|
|
1960
2047
|
}
|
|
1961
|
-
|
|
2048
|
+
BacktestKit.Backtest.stop(symbol, {
|
|
1962
2049
|
exchangeName,
|
|
1963
2050
|
strategyName,
|
|
1964
2051
|
frameName,
|
|
@@ -1982,7 +2069,7 @@ main$4();
|
|
|
1982
2069
|
|
|
1983
2070
|
const BEFORE_EXIT_FN$3 = functoolsKit.singleshot(async () => {
|
|
1984
2071
|
process.off("SIGINT", BEFORE_EXIT_FN$3);
|
|
1985
|
-
const [running = null] = await
|
|
2072
|
+
const [running = null] = await BacktestKit.Live.list();
|
|
1986
2073
|
if (!running) {
|
|
1987
2074
|
return;
|
|
1988
2075
|
}
|
|
@@ -1991,7 +2078,7 @@ const BEFORE_EXIT_FN$3 = functoolsKit.singleshot(async () => {
|
|
|
1991
2078
|
if (status === "fulfilled") {
|
|
1992
2079
|
return;
|
|
1993
2080
|
}
|
|
1994
|
-
|
|
2081
|
+
BacktestKit.Live.stop(symbol, {
|
|
1995
2082
|
exchangeName,
|
|
1996
2083
|
strategyName,
|
|
1997
2084
|
});
|
|
@@ -2014,7 +2101,7 @@ main$3();
|
|
|
2014
2101
|
|
|
2015
2102
|
const BEFORE_EXIT_FN$2 = functoolsKit.singleshot(async () => {
|
|
2016
2103
|
process.off("SIGINT", BEFORE_EXIT_FN$2);
|
|
2017
|
-
const [running = null] = await
|
|
2104
|
+
const [running = null] = await BacktestKit.Live.list();
|
|
2018
2105
|
if (!running) {
|
|
2019
2106
|
return;
|
|
2020
2107
|
}
|
|
@@ -2023,11 +2110,11 @@ const BEFORE_EXIT_FN$2 = functoolsKit.singleshot(async () => {
|
|
|
2023
2110
|
if (status === "fulfilled") {
|
|
2024
2111
|
return;
|
|
2025
2112
|
}
|
|
2026
|
-
|
|
2113
|
+
BacktestKit.Live.stop(symbol, {
|
|
2027
2114
|
exchangeName,
|
|
2028
2115
|
strategyName,
|
|
2029
2116
|
});
|
|
2030
|
-
|
|
2117
|
+
BacktestKit.listenDoneLive(cli.liveProviderService.disable);
|
|
2031
2118
|
});
|
|
2032
2119
|
const listenGracefulShutdown$2 = functoolsKit.singleshot(() => {
|
|
2033
2120
|
process.on("SIGINT", BEFORE_EXIT_FN$2);
|
package/build/index.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import * as BacktestKit from 'backtest-kit';
|
|
2
3
|
import { Storage, Notification, Markdown, Report, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, setConfig, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, listenSignal, listStrategySchema, overrideExchangeSchema, Backtest, Live, getCandles, checkCandles, warmCandles, listenRisk, listenStrategyCommit } from 'backtest-kit';
|
|
3
4
|
import { getErrorMessage, errorData, singleshot, str, BehaviorSubject, compose, execpool, queued, sleep, randomString, createAwaiter, TIMEOUT_SYMBOL, typo, retry, memoize, trycatch } from 'functools-kit';
|
|
4
5
|
import fs, { constants } from 'fs';
|
|
@@ -21,6 +22,8 @@ import MarkdownIt from 'markdown-it';
|
|
|
21
22
|
import sanitizeHtml from 'sanitize-html';
|
|
22
23
|
import { JSDOM } from 'jsdom';
|
|
23
24
|
import Mustache from 'mustache';
|
|
25
|
+
import { registerPlugin, transform } from '@babel/standalone';
|
|
26
|
+
import pluginUMD from '@babel/plugin-transform-modules-umd';
|
|
24
27
|
|
|
25
28
|
/**
|
|
26
29
|
* Fix for `Attempted to assign to readonly property (at redactToken)`
|
|
@@ -169,6 +172,7 @@ const baseServices$1 = {
|
|
|
169
172
|
errorService: Symbol('errorService'),
|
|
170
173
|
loggerService: Symbol('loggerService'),
|
|
171
174
|
resolveService: Symbol('resolveService'),
|
|
175
|
+
babelService: Symbol('babelService'),
|
|
172
176
|
};
|
|
173
177
|
const connectionServices$1 = {
|
|
174
178
|
moduleConnectionService: Symbol('moduleConnectionService'),
|
|
@@ -212,39 +216,52 @@ const TYPES = {
|
|
|
212
216
|
|
|
213
217
|
const entrySubject = new BehaviorSubject();
|
|
214
218
|
|
|
215
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
216
|
-
const __dirname = path.dirname(__filename);
|
|
217
|
-
|
|
219
|
+
const __filename$1 = fileURLToPath(import.meta.url);
|
|
220
|
+
const __dirname$1 = path.dirname(__filename$1);
|
|
221
|
+
createRequire(import.meta.url);
|
|
218
222
|
const REQUIRE_ENTRY_FACTORY = (filePath) => {
|
|
223
|
+
{
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
};
|
|
227
|
+
const IMPORT_ENTRY_FACTORY = async (filePath) => {
|
|
219
228
|
try {
|
|
220
|
-
|
|
229
|
+
await import(pathToFileURL(filePath).href);
|
|
221
230
|
return true;
|
|
222
231
|
}
|
|
223
232
|
catch {
|
|
224
233
|
return false;
|
|
225
234
|
}
|
|
226
235
|
};
|
|
227
|
-
const
|
|
228
|
-
await
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
236
|
+
const BABEL_ENTRY_FACTORY = async (filePath, self) => {
|
|
237
|
+
const code = await fs$1.readFile(filePath, "utf-8");
|
|
238
|
+
try {
|
|
239
|
+
await self.babelService.transpileAndRun(code);
|
|
240
|
+
return true;
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
console.log(getErrorMessage(error));
|
|
244
|
+
return false;
|
|
245
|
+
}
|
|
233
246
|
};
|
|
234
|
-
const LOAD_ENTRY_FN = async (filePath) => {
|
|
235
|
-
if (
|
|
236
|
-
await TSX_ENTRY_FACTORY(filePath);
|
|
247
|
+
const LOAD_ENTRY_FN = async (filePath, self) => {
|
|
248
|
+
if (REQUIRE_ENTRY_FACTORY()) {
|
|
237
249
|
return;
|
|
238
250
|
}
|
|
239
|
-
if (
|
|
240
|
-
|
|
251
|
+
if (await IMPORT_ENTRY_FACTORY(filePath)) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
if (await BABEL_ENTRY_FACTORY(filePath, self)) {
|
|
255
|
+
return;
|
|
241
256
|
}
|
|
257
|
+
throw new Error(`Failed to load entry point: ${filePath}`);
|
|
242
258
|
};
|
|
243
259
|
let _is_launched = false;
|
|
244
260
|
class ResolveService {
|
|
245
261
|
constructor() {
|
|
246
262
|
this.loggerService = inject(TYPES.loggerService);
|
|
247
|
-
this.
|
|
263
|
+
this.babelService = inject(TYPES.babelService);
|
|
264
|
+
this.DEFAULT_TEMPLATE_DIR = path.resolve(__dirname$1, '..', 'template');
|
|
248
265
|
this.OVERRIDE_TEMPLATE_DIR = path.resolve(process.cwd(), 'template');
|
|
249
266
|
this.OVERRIDE_MODULES_DIR = path.resolve(process.cwd(), 'modules');
|
|
250
267
|
this.attachEntryPoint = async (entryPoint) => {
|
|
@@ -260,7 +277,7 @@ class ResolveService {
|
|
|
260
277
|
process.chdir(moduleRoot);
|
|
261
278
|
dotenv.config({ path: path.join(cwd, '.env'), override: true, quiet: true });
|
|
262
279
|
dotenv.config({ path: path.join(moduleRoot, '.env'), override: true, quiet: true });
|
|
263
|
-
await LOAD_ENTRY_FN(absolutePath);
|
|
280
|
+
await LOAD_ENTRY_FN(absolutePath, this);
|
|
264
281
|
await entrySubject.next(absolutePath);
|
|
265
282
|
}
|
|
266
283
|
_is_launched = true;
|
|
@@ -1591,16 +1608,21 @@ class TelegramTemplateService {
|
|
|
1591
1608
|
}
|
|
1592
1609
|
}
|
|
1593
1610
|
|
|
1594
|
-
|
|
1611
|
+
createRequire(import.meta.url);
|
|
1595
1612
|
const getExtVariants = (fileName) => {
|
|
1596
1613
|
const ext = path.extname(fileName);
|
|
1597
1614
|
const base = ext ? fileName.slice(0, -ext.length) : fileName;
|
|
1598
1615
|
return [fileName, `${base}.cjs`, `${base}.mjs`];
|
|
1599
1616
|
};
|
|
1600
1617
|
const REQUIRE_MODULE_FACTORY = (fileName) => {
|
|
1618
|
+
{
|
|
1619
|
+
return null;
|
|
1620
|
+
}
|
|
1621
|
+
};
|
|
1622
|
+
const IMPORT_MODULE_FACTORY = async (fileName) => {
|
|
1601
1623
|
for (const variant of getExtVariants(fileName)) {
|
|
1602
1624
|
try {
|
|
1603
|
-
return
|
|
1625
|
+
return await import(pathToFileURL(variant).href);
|
|
1604
1626
|
}
|
|
1605
1627
|
catch {
|
|
1606
1628
|
continue;
|
|
@@ -1608,12 +1630,15 @@ const REQUIRE_MODULE_FACTORY = (fileName) => {
|
|
|
1608
1630
|
}
|
|
1609
1631
|
return null;
|
|
1610
1632
|
};
|
|
1611
|
-
const
|
|
1633
|
+
const BABEL_MODULE_FACTORY = async (fileName, self) => {
|
|
1612
1634
|
for (const variant of getExtVariants(fileName)) {
|
|
1613
1635
|
try {
|
|
1614
|
-
|
|
1636
|
+
const code = await fs$1.readFile(variant, "utf-8");
|
|
1637
|
+
const { exports } = self.babelService.transpileAndRun(code);
|
|
1638
|
+
return exports.default ?? exports;
|
|
1615
1639
|
}
|
|
1616
|
-
catch {
|
|
1640
|
+
catch (error) {
|
|
1641
|
+
console.log(getErrorMessage(error));
|
|
1617
1642
|
continue;
|
|
1618
1643
|
}
|
|
1619
1644
|
}
|
|
@@ -1628,18 +1653,22 @@ const LOAD_MODULE_MODULE_FN = async (fileName, self) => {
|
|
|
1628
1653
|
.then(() => true)
|
|
1629
1654
|
.catch(() => false);
|
|
1630
1655
|
const resolvedFile = hasOverride ? overridePath : targetPath;
|
|
1631
|
-
if ((Ctor = REQUIRE_MODULE_FACTORY(
|
|
1656
|
+
if ((Ctor = REQUIRE_MODULE_FACTORY())) {
|
|
1632
1657
|
return typeof Ctor === "function" ? new Ctor() : Ctor;
|
|
1633
1658
|
}
|
|
1634
1659
|
if ((Ctor = await IMPORT_MODULE_FACTORY(resolvedFile))) {
|
|
1635
1660
|
return typeof Ctor === "function" ? new Ctor() : Ctor;
|
|
1636
1661
|
}
|
|
1662
|
+
if ((Ctor = await BABEL_MODULE_FACTORY(resolvedFile, self))) {
|
|
1663
|
+
return typeof Ctor === "function" ? new Ctor() : Ctor;
|
|
1664
|
+
}
|
|
1637
1665
|
throw new Error(`Module module import failed for file: ${resolvedFile}`);
|
|
1638
1666
|
};
|
|
1639
1667
|
class ModuleConnectionService {
|
|
1640
1668
|
constructor() {
|
|
1641
1669
|
this.loggerService = inject(TYPES.loggerService);
|
|
1642
1670
|
this.resolveService = inject(TYPES.resolveService);
|
|
1671
|
+
this.babelService = inject(TYPES.babelService);
|
|
1643
1672
|
this.getInstance = memoize(([fileName]) => `${fileName}`, async (fileName) => {
|
|
1644
1673
|
this.loggerService.log("moduleConnectionService getInstance", {
|
|
1645
1674
|
fileName,
|
|
@@ -1833,6 +1862,62 @@ class LiveProviderService {
|
|
|
1833
1862
|
}
|
|
1834
1863
|
}
|
|
1835
1864
|
|
|
1865
|
+
registerPlugin("plugin-transform-modules-umd", pluginUMD);
|
|
1866
|
+
const require = createRequire(import.meta.url);
|
|
1867
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
1868
|
+
const __dirname = path.dirname(__filename);
|
|
1869
|
+
const BacktestKitCli = new Proxy({}, {
|
|
1870
|
+
get(_target, prop) {
|
|
1871
|
+
throw new Error(`@backtest-kit/cli is not available in this context (accessed: ${String(prop)})`);
|
|
1872
|
+
},
|
|
1873
|
+
});
|
|
1874
|
+
class BabelService {
|
|
1875
|
+
constructor() {
|
|
1876
|
+
this.loggerService = inject(TYPES.loggerService);
|
|
1877
|
+
this.transpile = (code) => {
|
|
1878
|
+
this.loggerService.log("babelService transpile", { codeLen: code.length });
|
|
1879
|
+
const result = transform(code, {
|
|
1880
|
+
filename: "index.ts",
|
|
1881
|
+
presets: ["env", "typescript"],
|
|
1882
|
+
plugins: [
|
|
1883
|
+
[
|
|
1884
|
+
"plugin-transform-modules-umd",
|
|
1885
|
+
{
|
|
1886
|
+
globals: {
|
|
1887
|
+
"backtest-kit": "BacktestKit",
|
|
1888
|
+
"@backtest-kit/cli": "BacktestKitCli",
|
|
1889
|
+
},
|
|
1890
|
+
moduleId: "Executor",
|
|
1891
|
+
},
|
|
1892
|
+
],
|
|
1893
|
+
],
|
|
1894
|
+
parserOpts: { strictMode: false },
|
|
1895
|
+
});
|
|
1896
|
+
if (!result.code) {
|
|
1897
|
+
throw new Error("BabelService transpile failed");
|
|
1898
|
+
}
|
|
1899
|
+
return result.code;
|
|
1900
|
+
};
|
|
1901
|
+
this.transpileAndRun = (code) => {
|
|
1902
|
+
this.loggerService.log("babelService transpileAndRun", {
|
|
1903
|
+
codeLen: code.length,
|
|
1904
|
+
});
|
|
1905
|
+
const module = { exports: {} };
|
|
1906
|
+
const exports = module.exports;
|
|
1907
|
+
eval(this.transpile(code));
|
|
1908
|
+
return {
|
|
1909
|
+
require,
|
|
1910
|
+
__filename,
|
|
1911
|
+
__dirname,
|
|
1912
|
+
exports,
|
|
1913
|
+
module,
|
|
1914
|
+
};
|
|
1915
|
+
};
|
|
1916
|
+
}
|
|
1917
|
+
}
|
|
1918
|
+
globalThis.BacktestKit = BacktestKit;
|
|
1919
|
+
globalThis.BacktestKitCli = BacktestKitCli;
|
|
1920
|
+
|
|
1836
1921
|
{
|
|
1837
1922
|
provide(TYPES.quickchartApiService, () => new QuickchartApiService());
|
|
1838
1923
|
provide(TYPES.telegramApiService, () => new TelegramApiService());
|
|
@@ -1841,6 +1926,7 @@ class LiveProviderService {
|
|
|
1841
1926
|
provide(TYPES.errorService, () => new ErrorService());
|
|
1842
1927
|
provide(TYPES.loggerService, () => new LoggerService());
|
|
1843
1928
|
provide(TYPES.resolveService, () => new ResolveService());
|
|
1929
|
+
provide(TYPES.babelService, () => new BabelService());
|
|
1844
1930
|
}
|
|
1845
1931
|
{
|
|
1846
1932
|
provide(TYPES.moduleConnectionService, () => new ModuleConnectionService());
|
|
@@ -1879,6 +1965,7 @@ const baseServices = {
|
|
|
1879
1965
|
errorService: inject(TYPES.errorService),
|
|
1880
1966
|
loggerService: inject(TYPES.loggerService),
|
|
1881
1967
|
resolveService: inject(TYPES.resolveService),
|
|
1968
|
+
babelService: inject(TYPES.babelService),
|
|
1882
1969
|
};
|
|
1883
1970
|
const connectionServices = {
|
|
1884
1971
|
moduleConnectionService: inject(TYPES.moduleConnectionService),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backtest-kit/cli",
|
|
3
|
-
"version": "3.3.
|
|
3
|
+
"version": "3.3.6",
|
|
4
4
|
"description": "Zero-boilerplate CLI runner for backtest-kit strategies. Run backtests, paper trading, and live bots with candle cache warming, web dashboard, and Telegram notifications — no setup code required.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Petr Tripolsky",
|
|
@@ -58,8 +58,10 @@
|
|
|
58
58
|
"default": "./build/index.cjs"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
+
"@babel/plugin-transform-modules-umd": "7.27.1",
|
|
62
|
+
"@babel/standalone": "7.29.1",
|
|
61
63
|
"@backtest-kit/ui": "3.3.2",
|
|
62
|
-
"
|
|
64
|
+
"@rollup/plugin-replace": "6.0.3",
|
|
63
65
|
"@rollup/plugin-typescript": "11.1.6",
|
|
64
66
|
"@types/image-size": "0.7.0",
|
|
65
67
|
"@types/jsdom": "21.1.7",
|
|
@@ -68,6 +70,7 @@
|
|
|
68
70
|
"@types/stack-trace": "0.0.33",
|
|
69
71
|
"backtest-kit": "3.3.2",
|
|
70
72
|
"glob": "11.0.1",
|
|
73
|
+
"markdown-it": "14.1.1",
|
|
71
74
|
"rimraf": "6.0.1",
|
|
72
75
|
"rollup": "3.29.5",
|
|
73
76
|
"rollup-plugin-dts": "6.1.1",
|
|
@@ -75,15 +78,15 @@
|
|
|
75
78
|
"ts-morph": "27.0.2",
|
|
76
79
|
"tslib": "2.7.0",
|
|
77
80
|
"typedoc": "0.27.9",
|
|
78
|
-
"tsx": "4.19.3",
|
|
79
81
|
"worker-testbed": "1.0.12"
|
|
80
82
|
},
|
|
81
83
|
"peerDependencies": {
|
|
82
|
-
"
|
|
84
|
+
"@babel/plugin-transform-modules-umd": "^7.27.1",
|
|
85
|
+
"@babel/standalone": "^7.29.1",
|
|
83
86
|
"@backtest-kit/ui": "^3.3.2",
|
|
84
87
|
"backtest-kit": "^3.3.2",
|
|
85
88
|
"markdown-it": "^14.1.1",
|
|
86
|
-
"
|
|
89
|
+
"typescript": "^5.0.0"
|
|
87
90
|
},
|
|
88
91
|
"dependencies": {
|
|
89
92
|
"ccxt": "4.5.39",
|
package/types.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as functools_kit from 'functools-kit';
|
|
2
|
+
import * as BacktestKit from 'backtest-kit';
|
|
2
3
|
import { CandleInterval, TrailingTakeCommit, TrailingStopCommit, BreakevenCommit, PartialProfitCommit, PartialLossCommit, IStrategyTickResultScheduled, IStrategyTickResultCancelled, IStrategyTickResultOpened, IStrategyTickResultClosed, RiskContract, AverageBuyCommit } from 'backtest-kit';
|
|
3
4
|
import { Input } from 'telegraf';
|
|
4
5
|
|
|
@@ -85,8 +86,30 @@ declare class FrameSchemaService {
|
|
|
85
86
|
addSchema: (() => Promise<void>) & functools_kit.ISingleshotClearable;
|
|
86
87
|
}
|
|
87
88
|
|
|
89
|
+
declare const BacktestKitCli: {};
|
|
90
|
+
declare global {
|
|
91
|
+
interface Window {
|
|
92
|
+
BacktestKit: typeof BacktestKit;
|
|
93
|
+
BacktestKitCli: typeof BacktestKitCli;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
declare class BabelService {
|
|
97
|
+
readonly loggerService: LoggerService;
|
|
98
|
+
transpile: (code: string) => any;
|
|
99
|
+
transpileAndRun: (code: string) => {
|
|
100
|
+
require: NodeRequire;
|
|
101
|
+
__filename: string;
|
|
102
|
+
__dirname: string;
|
|
103
|
+
exports: Record<string, unknown>;
|
|
104
|
+
module: {
|
|
105
|
+
exports: Record<string, unknown>;
|
|
106
|
+
};
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
88
110
|
declare class ResolveService {
|
|
89
|
-
|
|
111
|
+
readonly loggerService: LoggerService;
|
|
112
|
+
readonly babelService: BabelService;
|
|
90
113
|
readonly DEFAULT_TEMPLATE_DIR: string;
|
|
91
114
|
readonly OVERRIDE_TEMPLATE_DIR: string;
|
|
92
115
|
readonly OVERRIDE_MODULES_DIR: string;
|
|
@@ -203,6 +226,7 @@ type TBaseModuleCtor = new () => BaseModule;
|
|
|
203
226
|
declare class ModuleConnectionService {
|
|
204
227
|
readonly loggerService: LoggerService;
|
|
205
228
|
readonly resolveService: ResolveService;
|
|
229
|
+
readonly babelService: BabelService;
|
|
206
230
|
getInstance: ((fileName: string) => Promise<BaseModule>) & functools_kit.IClearableMemoize<string> & functools_kit.IControlMemoize<string, Promise<Partial<ILiveModule>>>;
|
|
207
231
|
}
|
|
208
232
|
|
|
@@ -243,6 +267,7 @@ declare const cli: {
|
|
|
243
267
|
errorService: ErrorService;
|
|
244
268
|
loggerService: LoggerService;
|
|
245
269
|
resolveService: ResolveService;
|
|
270
|
+
babelService: BabelService;
|
|
246
271
|
telegramApiService: TelegramApiService;
|
|
247
272
|
quickchartApiService: QuickchartApiService;
|
|
248
273
|
};
|