@backtest-kit/cli 0.0.1 → 0.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/README.md +124 -41
- package/build/index.cjs +241 -112
- package/build/index.mjs +242 -114
- package/package.json +19 -3
- package/template/project/.gitkeep +0 -0
- package/types.d.ts +50 -16
package/build/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Storage, Notification, Markdown, Report, StorageLive, StorageBacktest, NotificationLive, NotificationBacktest, listExchangeSchema, addExchangeSchema, roundTicks, listFrameSchema, addFrameSchema, listenDoneLive, listenDoneBacktest, listStrategySchema, overrideExchangeSchema, Backtest, Live, getCandles, checkCandles, warmCandles, listenRisk, listenSignal, listenStrategyCommit } from 'backtest-kit';
|
|
2
|
-
import { getErrorMessage, errorData, str, BehaviorSubject,
|
|
2
|
+
import { getErrorMessage, errorData, singleshot, str, BehaviorSubject, compose, execpool, queued, sleep, randomString, createAwaiter, TIMEOUT_SYMBOL, typo, retry, memoize, trycatch } from 'functools-kit';
|
|
3
3
|
import fs, { constants } from 'fs';
|
|
4
4
|
import * as stackTrace from 'stack-trace';
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
@@ -112,14 +112,14 @@ class ErrorService {
|
|
|
112
112
|
this.handleGlobalError(err);
|
|
113
113
|
});
|
|
114
114
|
};
|
|
115
|
-
this.init = () => {
|
|
115
|
+
this.init = singleshot(() => {
|
|
116
116
|
const global = globalThis;
|
|
117
117
|
if (global[ERROR_HANDLER_INSTALLED]) {
|
|
118
118
|
return;
|
|
119
119
|
}
|
|
120
120
|
this._listenForError();
|
|
121
121
|
global[ERROR_HANDLER_INSTALLED] = 1;
|
|
122
|
-
};
|
|
122
|
+
});
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
@@ -314,8 +314,8 @@ const ADD_EXCHANGE_FN = (self) => {
|
|
|
314
314
|
class ExchangeSchemaService {
|
|
315
315
|
constructor() {
|
|
316
316
|
this.loggerService = inject(TYPES.loggerService);
|
|
317
|
-
this.
|
|
318
|
-
this.loggerService.log("exchangeSchemaService
|
|
317
|
+
this.addSchema = singleshot(async () => {
|
|
318
|
+
this.loggerService.log("exchangeSchemaService addSchema");
|
|
319
319
|
const { length } = await listExchangeSchema();
|
|
320
320
|
!length && ADD_EXCHANGE_FN(this);
|
|
321
321
|
});
|
|
@@ -399,8 +399,8 @@ const ADD_FRAME_FN = (self) => {
|
|
|
399
399
|
class FrameSchemaService {
|
|
400
400
|
constructor() {
|
|
401
401
|
this.loggerService = inject(TYPES.loggerService);
|
|
402
|
-
this.
|
|
403
|
-
this.loggerService.log("frameSchemaService
|
|
402
|
+
this.addSchema = singleshot(async () => {
|
|
403
|
+
this.loggerService.log("frameSchemaService addSchema");
|
|
404
404
|
if (!getArgs().values.backtest) {
|
|
405
405
|
return;
|
|
406
406
|
}
|
|
@@ -413,8 +413,8 @@ class FrameSchemaService {
|
|
|
413
413
|
class SymbolSchemaService {
|
|
414
414
|
constructor() {
|
|
415
415
|
this.loggerService = inject(TYPES.loggerService);
|
|
416
|
-
this.
|
|
417
|
-
this.loggerService.log("symbolSchemaService
|
|
416
|
+
this.addSchema = singleshot(async () => {
|
|
417
|
+
this.loggerService.log("symbolSchemaService addSchema");
|
|
418
418
|
if (!getArgs().values.symbol) {
|
|
419
419
|
console.warn("Warning: The default symbol is set to BTCUSDT. Please make sure to update it according to your needs using --symbol cli param.");
|
|
420
420
|
}
|
|
@@ -435,56 +435,69 @@ const notifyFinish = singleshot(() => {
|
|
|
435
435
|
disposeRef = compose(() => unLive(), () => unBacktest());
|
|
436
436
|
});
|
|
437
437
|
|
|
438
|
+
const getEntry = (metaUrl) => {
|
|
439
|
+
return process.argv[1] === new URL(metaUrl).pathname;
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
const DEFAULT_CACHE_LIST = ["1m", "15m", "30m", "1h", "4h"];
|
|
443
|
+
const GET_CACHE_LIST_FN = () => {
|
|
444
|
+
const { values } = getArgs();
|
|
445
|
+
if (!values.cache) {
|
|
446
|
+
console.warn(`Warning: No cache timeframes provided. Using default timeframes: ${DEFAULT_CACHE_LIST.join(", ")}`);
|
|
447
|
+
return DEFAULT_CACHE_LIST;
|
|
448
|
+
}
|
|
449
|
+
return String(values.cache)
|
|
450
|
+
.split(",")
|
|
451
|
+
.map((timeframe) => timeframe.trim());
|
|
452
|
+
};
|
|
438
453
|
class BacktestMainService {
|
|
439
454
|
constructor() {
|
|
440
455
|
this.loggerService = inject(TYPES.loggerService);
|
|
456
|
+
this.resolveService = inject(TYPES.resolveService);
|
|
441
457
|
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
442
458
|
this.frameSchemaService = inject(TYPES.frameSchemaService);
|
|
459
|
+
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
443
460
|
this.cacheLogicService = inject(TYPES.cacheLogicService);
|
|
444
|
-
this.resolveService = inject(TYPES.resolveService);
|
|
445
461
|
this.frontendProviderService = inject(TYPES.frontendProviderService);
|
|
446
462
|
this.telegramProviderService = inject(TYPES.telegramProviderService);
|
|
447
|
-
this.
|
|
448
|
-
this.loggerService.log("backtestMainService
|
|
463
|
+
this.run = singleshot(async (payload) => {
|
|
464
|
+
this.loggerService.log("backtestMainService run", {
|
|
465
|
+
payload,
|
|
466
|
+
});
|
|
449
467
|
{
|
|
450
|
-
this.frontendProviderService.
|
|
451
|
-
this.telegramProviderService.
|
|
452
|
-
}
|
|
453
|
-
const { values, positionals } = getArgs();
|
|
454
|
-
if (!values.backtest) {
|
|
455
|
-
return;
|
|
456
|
-
}
|
|
457
|
-
const [entryPoint = null] = positionals;
|
|
458
|
-
if (!entryPoint) {
|
|
459
|
-
throw new Error("Entry point is required");
|
|
468
|
+
this.frontendProviderService.connect();
|
|
469
|
+
this.telegramProviderService.connect();
|
|
460
470
|
}
|
|
461
|
-
await this.resolveService.attachEntryPoint(entryPoint);
|
|
471
|
+
await this.resolveService.attachEntryPoint(payload.entryPoint);
|
|
462
472
|
{
|
|
463
|
-
this.exchangeSchemaService.
|
|
464
|
-
this.
|
|
473
|
+
this.exchangeSchemaService.addSchema();
|
|
474
|
+
this.symbolSchemaService.addSchema();
|
|
475
|
+
this.frameSchemaService.addSchema();
|
|
465
476
|
}
|
|
466
|
-
const symbol =
|
|
477
|
+
const symbol = payload.symbol || "BTCUSDT";
|
|
467
478
|
const [defaultStrategyName = null] = await listStrategySchema();
|
|
468
479
|
const [defaultExchangeName = null] = await listExchangeSchema();
|
|
469
480
|
const [defaultFrameName = null] = await listFrameSchema();
|
|
470
|
-
const strategyName =
|
|
481
|
+
const strategyName = payload.strategy || defaultStrategyName?.strategyName;
|
|
471
482
|
if (!strategyName) {
|
|
472
483
|
throw new Error("Strategy name is required");
|
|
473
484
|
}
|
|
474
|
-
const exchangeName =
|
|
485
|
+
const exchangeName = payload.exchange || defaultExchangeName?.exchangeName;
|
|
475
486
|
if (!exchangeName) {
|
|
476
487
|
throw new Error("Exchange name is required");
|
|
477
488
|
}
|
|
478
|
-
const frameName =
|
|
489
|
+
const frameName = payload.frame || defaultFrameName?.frameName;
|
|
479
490
|
if (!frameName) {
|
|
480
491
|
throw new Error("Frame name is required");
|
|
481
492
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
493
|
+
{
|
|
494
|
+
await this.cacheLogicService.execute(payload.cacheList, {
|
|
495
|
+
exchangeName,
|
|
496
|
+
frameName,
|
|
497
|
+
symbol,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
if (payload.verbose) {
|
|
488
501
|
overrideExchangeSchema({
|
|
489
502
|
exchangeName,
|
|
490
503
|
callbacks: {
|
|
@@ -501,46 +514,68 @@ class BacktestMainService {
|
|
|
501
514
|
});
|
|
502
515
|
notifyFinish();
|
|
503
516
|
});
|
|
517
|
+
this.connect = singleshot(async () => {
|
|
518
|
+
this.loggerService.log("backtestMainService connect");
|
|
519
|
+
if (!getEntry(import.meta.url)) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
522
|
+
const { values, positionals } = getArgs();
|
|
523
|
+
if (!values.backtest) {
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
const [entryPoint = null] = positionals;
|
|
527
|
+
if (!entryPoint) {
|
|
528
|
+
throw new Error("Entry point is required");
|
|
529
|
+
}
|
|
530
|
+
const cacheList = GET_CACHE_LIST_FN();
|
|
531
|
+
return await this.run({
|
|
532
|
+
symbol: values.symbol,
|
|
533
|
+
entryPoint,
|
|
534
|
+
cacheList,
|
|
535
|
+
exchange: values.exchange,
|
|
536
|
+
frame: values.frame,
|
|
537
|
+
strategy: values.strategy,
|
|
538
|
+
verbose: values.verbose,
|
|
539
|
+
});
|
|
540
|
+
});
|
|
504
541
|
}
|
|
505
542
|
}
|
|
506
543
|
|
|
507
544
|
class LiveMainService {
|
|
508
545
|
constructor() {
|
|
509
546
|
this.loggerService = inject(TYPES.loggerService);
|
|
510
|
-
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
511
547
|
this.resolveService = inject(TYPES.resolveService);
|
|
548
|
+
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
549
|
+
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
512
550
|
this.frontendProviderService = inject(TYPES.frontendProviderService);
|
|
513
551
|
this.telegramProviderService = inject(TYPES.telegramProviderService);
|
|
514
|
-
this.
|
|
515
|
-
|
|
552
|
+
this.liveProviderService = inject(TYPES.liveProviderService);
|
|
553
|
+
this.run = singleshot(async (payload) => {
|
|
554
|
+
this.loggerService.log("liveMainService run", {
|
|
555
|
+
payload,
|
|
556
|
+
});
|
|
516
557
|
{
|
|
517
|
-
this.frontendProviderService.
|
|
518
|
-
this.telegramProviderService.
|
|
519
|
-
|
|
520
|
-
const { values, positionals } = getArgs();
|
|
521
|
-
if (!values.live) {
|
|
522
|
-
return;
|
|
558
|
+
this.frontendProviderService.connect();
|
|
559
|
+
this.telegramProviderService.connect();
|
|
560
|
+
this.liveProviderService.connect();
|
|
523
561
|
}
|
|
524
|
-
|
|
525
|
-
if (!entryPoint) {
|
|
526
|
-
throw new Error("Entry point is required");
|
|
527
|
-
}
|
|
528
|
-
await this.resolveService.attachEntryPoint(entryPoint);
|
|
562
|
+
await this.resolveService.attachEntryPoint(payload.entryPoint);
|
|
529
563
|
{
|
|
530
|
-
this.exchangeSchemaService.
|
|
564
|
+
this.exchangeSchemaService.addSchema();
|
|
565
|
+
this.symbolSchemaService.addSchema();
|
|
531
566
|
}
|
|
532
|
-
const symbol =
|
|
567
|
+
const symbol = payload.symbol || "BTCUSDT";
|
|
533
568
|
const [defaultStrategyName = null] = await listStrategySchema();
|
|
534
569
|
const [defaultExchangeName = null] = await listExchangeSchema();
|
|
535
|
-
const strategyName =
|
|
570
|
+
const strategyName = payload.strategy || defaultStrategyName?.strategyName;
|
|
536
571
|
if (!strategyName) {
|
|
537
572
|
throw new Error("Strategy name is required");
|
|
538
573
|
}
|
|
539
|
-
const exchangeName =
|
|
574
|
+
const exchangeName = payload.exchange || defaultExchangeName?.exchangeName;
|
|
540
575
|
if (!exchangeName) {
|
|
541
576
|
throw new Error("Exchange name is required");
|
|
542
577
|
}
|
|
543
|
-
if (
|
|
578
|
+
if (payload.verbose) {
|
|
544
579
|
overrideExchangeSchema({
|
|
545
580
|
exchangeName,
|
|
546
581
|
callbacks: {
|
|
@@ -556,46 +591,61 @@ class LiveMainService {
|
|
|
556
591
|
});
|
|
557
592
|
notifyFinish();
|
|
558
593
|
});
|
|
594
|
+
this.connect = singleshot(async () => {
|
|
595
|
+
this.loggerService.log("liveMainService connect");
|
|
596
|
+
if (!getEntry(import.meta.url)) {
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const { values, positionals } = getArgs();
|
|
600
|
+
if (!values.live) {
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
const [entryPoint = null] = positionals;
|
|
604
|
+
if (!entryPoint) {
|
|
605
|
+
throw new Error("Entry point is required");
|
|
606
|
+
}
|
|
607
|
+
return await this.run({
|
|
608
|
+
entryPoint,
|
|
609
|
+
exchange: values.exchange,
|
|
610
|
+
strategy: values.strategy,
|
|
611
|
+
symbol: values.symbol,
|
|
612
|
+
verbose: values.verbose,
|
|
613
|
+
});
|
|
614
|
+
});
|
|
559
615
|
}
|
|
560
616
|
}
|
|
561
617
|
|
|
562
618
|
class PaperMainService {
|
|
563
619
|
constructor() {
|
|
564
620
|
this.loggerService = inject(TYPES.loggerService);
|
|
565
|
-
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
566
621
|
this.resolveService = inject(TYPES.resolveService);
|
|
622
|
+
this.exchangeSchemaService = inject(TYPES.exchangeSchemaService);
|
|
623
|
+
this.symbolSchemaService = inject(TYPES.symbolSchemaService);
|
|
567
624
|
this.frontendProviderService = inject(TYPES.frontendProviderService);
|
|
568
625
|
this.telegramProviderService = inject(TYPES.telegramProviderService);
|
|
569
|
-
this.
|
|
626
|
+
this.run = singleshot(async (payload) => {
|
|
570
627
|
this.loggerService.log("paperMainService init");
|
|
571
628
|
{
|
|
572
|
-
this.frontendProviderService.
|
|
573
|
-
this.telegramProviderService.
|
|
629
|
+
this.frontendProviderService.connect();
|
|
630
|
+
this.telegramProviderService.connect();
|
|
574
631
|
}
|
|
575
|
-
|
|
576
|
-
if (!values.paper) {
|
|
577
|
-
return;
|
|
578
|
-
}
|
|
579
|
-
const [entryPoint = null] = positionals;
|
|
580
|
-
if (!entryPoint) {
|
|
581
|
-
throw new Error("Entry point is required");
|
|
582
|
-
}
|
|
583
|
-
await this.resolveService.attachEntryPoint(entryPoint);
|
|
632
|
+
await this.resolveService.attachEntryPoint(payload.entryPoint);
|
|
584
633
|
{
|
|
585
|
-
this.exchangeSchemaService.
|
|
634
|
+
this.exchangeSchemaService.addSchema();
|
|
635
|
+
this.symbolSchemaService.addSchema();
|
|
586
636
|
}
|
|
587
|
-
const symbol =
|
|
637
|
+
const symbol = payload.symbol || "BTCUSDT";
|
|
588
638
|
const [defaultStrategyName = null] = await listStrategySchema();
|
|
589
639
|
const [defaultExchangeName = null] = await listExchangeSchema();
|
|
590
|
-
const strategyName =
|
|
640
|
+
const strategyName = payload.strategy || defaultStrategyName?.strategyName;
|
|
591
641
|
if (!strategyName) {
|
|
592
642
|
throw new Error("Strategy name is required");
|
|
593
643
|
}
|
|
594
|
-
const exchangeName =
|
|
644
|
+
const exchangeName = payload.exchange || defaultExchangeName?.exchangeName;
|
|
595
645
|
if (!exchangeName) {
|
|
596
646
|
throw new Error("Exchange name is required");
|
|
597
647
|
}
|
|
598
|
-
if (
|
|
648
|
+
if (payload.verbose) {
|
|
599
649
|
overrideExchangeSchema({
|
|
600
650
|
exchangeName,
|
|
601
651
|
callbacks: {
|
|
@@ -611,6 +661,27 @@ class PaperMainService {
|
|
|
611
661
|
});
|
|
612
662
|
notifyFinish();
|
|
613
663
|
});
|
|
664
|
+
this.connect = singleshot(async () => {
|
|
665
|
+
this.loggerService.log("paperMainService connect");
|
|
666
|
+
if (!getEntry(import.meta.url)) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
669
|
+
const { values, positionals } = getArgs();
|
|
670
|
+
if (!values.paper) {
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
const [entryPoint = null] = positionals;
|
|
674
|
+
if (!entryPoint) {
|
|
675
|
+
throw new Error("Entry point is required");
|
|
676
|
+
}
|
|
677
|
+
return await this.run({
|
|
678
|
+
entryPoint,
|
|
679
|
+
exchange: values.exchange,
|
|
680
|
+
strategy: values.strategy,
|
|
681
|
+
symbol: values.symbol,
|
|
682
|
+
verbose: values.verbose,
|
|
683
|
+
});
|
|
684
|
+
});
|
|
614
685
|
}
|
|
615
686
|
}
|
|
616
687
|
|
|
@@ -646,12 +717,12 @@ class FrontendProviderService {
|
|
|
646
717
|
lastSubscription();
|
|
647
718
|
}
|
|
648
719
|
};
|
|
649
|
-
this.
|
|
650
|
-
this.loggerService.log("frontendProviderService
|
|
720
|
+
this.connect = singleshot(async () => {
|
|
721
|
+
this.loggerService.log("frontendProviderService connect");
|
|
651
722
|
if (!getArgs().values.ui) {
|
|
652
723
|
return;
|
|
653
724
|
}
|
|
654
|
-
entrySubject.subscribe(this.enable);
|
|
725
|
+
return entrySubject.subscribe(this.enable);
|
|
655
726
|
});
|
|
656
727
|
}
|
|
657
728
|
}
|
|
@@ -682,12 +753,12 @@ class TelegramProviderService {
|
|
|
682
753
|
lastSubscription();
|
|
683
754
|
}
|
|
684
755
|
};
|
|
685
|
-
this.
|
|
686
|
-
this.loggerService.log("telegramProviderService
|
|
756
|
+
this.connect = singleshot(async () => {
|
|
757
|
+
this.loggerService.log("telegramProviderService connect");
|
|
687
758
|
if (!getArgs().values.telegram) {
|
|
688
759
|
return;
|
|
689
760
|
}
|
|
690
|
-
entrySubject.subscribe(this.enable);
|
|
761
|
+
return entrySubject.subscribe(this.enable);
|
|
691
762
|
});
|
|
692
763
|
}
|
|
693
764
|
}
|
|
@@ -1109,17 +1180,6 @@ class TelegramWebService {
|
|
|
1109
1180
|
}
|
|
1110
1181
|
}
|
|
1111
1182
|
|
|
1112
|
-
const DEFAULT_TIMEFRAME_LIST = ["1m", "15m", "30m", "1h", "4h"];
|
|
1113
|
-
const GET_TIMEFRAME_LIST_FN = async () => {
|
|
1114
|
-
const { values } = getArgs();
|
|
1115
|
-
if (!values.cache) {
|
|
1116
|
-
console.warn(`Warning: No cache timeframes provided. Using default timeframes: ${DEFAULT_TIMEFRAME_LIST.join(", ")}`);
|
|
1117
|
-
return DEFAULT_TIMEFRAME_LIST;
|
|
1118
|
-
}
|
|
1119
|
-
return String(values.cache)
|
|
1120
|
-
.split(",")
|
|
1121
|
-
.map((timeframe) => timeframe.trim());
|
|
1122
|
-
};
|
|
1123
1183
|
const GET_TIMEFRAME_RANGE_FN = async (frameName) => {
|
|
1124
1184
|
const frameList = await listFrameSchema();
|
|
1125
1185
|
const frameSchema = frameList.find((frameSchema) => frameSchema.frameName === frameName);
|
|
@@ -1155,12 +1215,11 @@ const CACHE_CANDLES_FN = retry(async (interval, dto) => {
|
|
|
1155
1215
|
class CacheLogicService {
|
|
1156
1216
|
constructor() {
|
|
1157
1217
|
this.loggerService = inject(TYPES.loggerService);
|
|
1158
|
-
this.execute = async (dto) => {
|
|
1218
|
+
this.execute = async (intervalList, dto) => {
|
|
1159
1219
|
this.loggerService.log("cacheLogicService execute", {
|
|
1160
1220
|
dto,
|
|
1161
1221
|
});
|
|
1162
1222
|
const { startDate, endDate } = await GET_TIMEFRAME_RANGE_FN(dto.frameName);
|
|
1163
|
-
const intervalList = await GET_TIMEFRAME_LIST_FN();
|
|
1164
1223
|
try {
|
|
1165
1224
|
for (const interval of intervalList) {
|
|
1166
1225
|
await CACHE_CANDLES_FN(interval, {
|
|
@@ -1333,7 +1392,8 @@ class TelegramLogicService {
|
|
|
1333
1392
|
return;
|
|
1334
1393
|
}
|
|
1335
1394
|
});
|
|
1336
|
-
const
|
|
1395
|
+
const unConnect = () => this.connect.clear();
|
|
1396
|
+
const unListen = compose(() => unRisk(), () => unSignal(), () => unCommit(), () => unConnect());
|
|
1337
1397
|
return () => {
|
|
1338
1398
|
STOP_BOT_FN();
|
|
1339
1399
|
unListen();
|
|
@@ -1483,10 +1543,10 @@ class ModuleConnectionService {
|
|
|
1483
1543
|
}
|
|
1484
1544
|
}
|
|
1485
1545
|
|
|
1486
|
-
const LOAD_INSTANCE_FN = singleshot(async (self) => {
|
|
1546
|
+
const LOAD_INSTANCE_FN = singleshot(trycatch(async (self) => {
|
|
1487
1547
|
const module = (await self.moduleConnectionService.getInstance("./live.module"));
|
|
1488
1548
|
return module;
|
|
1489
|
-
});
|
|
1549
|
+
}, { defaultValue: null }));
|
|
1490
1550
|
class LiveProviderService {
|
|
1491
1551
|
constructor() {
|
|
1492
1552
|
this.loggerService = inject(TYPES.loggerService);
|
|
@@ -1496,7 +1556,7 @@ class LiveProviderService {
|
|
|
1496
1556
|
event,
|
|
1497
1557
|
});
|
|
1498
1558
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1499
|
-
if (instance
|
|
1559
|
+
if (instance?.onTrailingTake) {
|
|
1500
1560
|
await instance.onTrailingTake(event);
|
|
1501
1561
|
}
|
|
1502
1562
|
};
|
|
@@ -1505,7 +1565,7 @@ class LiveProviderService {
|
|
|
1505
1565
|
event,
|
|
1506
1566
|
});
|
|
1507
1567
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1508
|
-
if (instance
|
|
1568
|
+
if (instance?.onTrailingStop) {
|
|
1509
1569
|
await instance.onTrailingStop(event);
|
|
1510
1570
|
}
|
|
1511
1571
|
};
|
|
@@ -1514,7 +1574,7 @@ class LiveProviderService {
|
|
|
1514
1574
|
event,
|
|
1515
1575
|
});
|
|
1516
1576
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1517
|
-
if (instance
|
|
1577
|
+
if (instance?.onBreakeven) {
|
|
1518
1578
|
await instance.onBreakeven(event);
|
|
1519
1579
|
}
|
|
1520
1580
|
};
|
|
@@ -1523,7 +1583,7 @@ class LiveProviderService {
|
|
|
1523
1583
|
event,
|
|
1524
1584
|
});
|
|
1525
1585
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1526
|
-
if (instance
|
|
1586
|
+
if (instance?.onPartialProfit) {
|
|
1527
1587
|
await instance.onPartialProfit(event);
|
|
1528
1588
|
}
|
|
1529
1589
|
};
|
|
@@ -1532,7 +1592,7 @@ class LiveProviderService {
|
|
|
1532
1592
|
event,
|
|
1533
1593
|
});
|
|
1534
1594
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1535
|
-
if (instance
|
|
1595
|
+
if (instance?.onPartialLoss) {
|
|
1536
1596
|
await instance.onPartialLoss(event);
|
|
1537
1597
|
}
|
|
1538
1598
|
};
|
|
@@ -1541,7 +1601,7 @@ class LiveProviderService {
|
|
|
1541
1601
|
event,
|
|
1542
1602
|
});
|
|
1543
1603
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1544
|
-
if (instance
|
|
1604
|
+
if (instance?.onScheduled) {
|
|
1545
1605
|
await instance.onScheduled(event);
|
|
1546
1606
|
}
|
|
1547
1607
|
};
|
|
@@ -1550,7 +1610,7 @@ class LiveProviderService {
|
|
|
1550
1610
|
event,
|
|
1551
1611
|
});
|
|
1552
1612
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1553
|
-
if (instance
|
|
1613
|
+
if (instance?.onCancelled) {
|
|
1554
1614
|
await instance.onCancelled(event);
|
|
1555
1615
|
}
|
|
1556
1616
|
};
|
|
@@ -1559,7 +1619,7 @@ class LiveProviderService {
|
|
|
1559
1619
|
event,
|
|
1560
1620
|
});
|
|
1561
1621
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1562
|
-
if (instance
|
|
1622
|
+
if (instance?.onOpened) {
|
|
1563
1623
|
await instance.onOpened(event);
|
|
1564
1624
|
}
|
|
1565
1625
|
};
|
|
@@ -1568,7 +1628,7 @@ class LiveProviderService {
|
|
|
1568
1628
|
event,
|
|
1569
1629
|
});
|
|
1570
1630
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1571
|
-
if (instance
|
|
1631
|
+
if (instance?.onClosed) {
|
|
1572
1632
|
await instance.onClosed(event);
|
|
1573
1633
|
}
|
|
1574
1634
|
};
|
|
@@ -1577,12 +1637,20 @@ class LiveProviderService {
|
|
|
1577
1637
|
event,
|
|
1578
1638
|
});
|
|
1579
1639
|
const instance = await LOAD_INSTANCE_FN(this);
|
|
1580
|
-
if (instance
|
|
1640
|
+
if (instance?.onRisk) {
|
|
1581
1641
|
await instance.onRisk(event);
|
|
1582
1642
|
}
|
|
1583
1643
|
};
|
|
1584
1644
|
this.enable = singleshot(() => {
|
|
1585
1645
|
this.loggerService.log("liveProviderService enable");
|
|
1646
|
+
LOAD_INSTANCE_FN(this).then((module) => {
|
|
1647
|
+
if (module) {
|
|
1648
|
+
this.loggerService.log("Live trading initialized successfully with ./modules/live.module.mjs");
|
|
1649
|
+
return;
|
|
1650
|
+
}
|
|
1651
|
+
console.log("No ./modules/live.module.mjs found, live trading failed to initialize");
|
|
1652
|
+
process.exit(-1);
|
|
1653
|
+
});
|
|
1586
1654
|
const unRisk = listenRisk(async (event) => {
|
|
1587
1655
|
await this.handleRisk(event);
|
|
1588
1656
|
});
|
|
@@ -1626,7 +1694,8 @@ class LiveProviderService {
|
|
|
1626
1694
|
return;
|
|
1627
1695
|
}
|
|
1628
1696
|
});
|
|
1629
|
-
|
|
1697
|
+
const unConnect = () => this.enable.clear();
|
|
1698
|
+
return compose(() => unRisk(), () => unSignal(), () => unCommit(), () => unConnect());
|
|
1630
1699
|
});
|
|
1631
1700
|
this.disable = () => {
|
|
1632
1701
|
this.loggerService.log("liveProviderService disable");
|
|
@@ -1635,12 +1704,12 @@ class LiveProviderService {
|
|
|
1635
1704
|
lastSubscription();
|
|
1636
1705
|
}
|
|
1637
1706
|
};
|
|
1638
|
-
this.
|
|
1639
|
-
this.loggerService.log("liveProviderService
|
|
1707
|
+
this.connect = singleshot(async () => {
|
|
1708
|
+
this.loggerService.log("liveProviderService connect");
|
|
1640
1709
|
if (!getArgs().values.live) {
|
|
1641
1710
|
return;
|
|
1642
1711
|
}
|
|
1643
|
-
entrySubject.subscribe(this.enable);
|
|
1712
|
+
return entrySubject.subscribe(this.enable);
|
|
1644
1713
|
});
|
|
1645
1714
|
}
|
|
1646
1715
|
}
|
|
@@ -1754,12 +1823,19 @@ const BEFORE_EXIT_FN$4 = singleshot(async () => {
|
|
|
1754
1823
|
frameName,
|
|
1755
1824
|
});
|
|
1756
1825
|
});
|
|
1826
|
+
const listenGracefulShutdown$4 = singleshot(() => {
|
|
1827
|
+
process.on("SIGINT", BEFORE_EXIT_FN$4);
|
|
1828
|
+
});
|
|
1757
1829
|
const main$4 = async () => {
|
|
1830
|
+
if (!getEntry(import.meta.url)) {
|
|
1831
|
+
return;
|
|
1832
|
+
}
|
|
1758
1833
|
const { values } = getArgs();
|
|
1759
1834
|
if (!values.backtest) {
|
|
1760
1835
|
return;
|
|
1761
1836
|
}
|
|
1762
|
-
|
|
1837
|
+
await cli.backtestMainService.connect();
|
|
1838
|
+
listenGracefulShutdown$4();
|
|
1763
1839
|
};
|
|
1764
1840
|
main$4();
|
|
1765
1841
|
|
|
@@ -1779,12 +1855,19 @@ const BEFORE_EXIT_FN$3 = singleshot(async () => {
|
|
|
1779
1855
|
strategyName,
|
|
1780
1856
|
});
|
|
1781
1857
|
});
|
|
1858
|
+
const listenGracefulShutdown$3 = singleshot(() => {
|
|
1859
|
+
process.on("SIGINT", BEFORE_EXIT_FN$3);
|
|
1860
|
+
});
|
|
1782
1861
|
const main$3 = async () => {
|
|
1862
|
+
if (!getEntry(import.meta.url)) {
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1783
1865
|
const { values } = getArgs();
|
|
1784
1866
|
if (!values.paper) {
|
|
1785
1867
|
return;
|
|
1786
1868
|
}
|
|
1787
|
-
|
|
1869
|
+
cli.paperMainService.connect();
|
|
1870
|
+
listenGracefulShutdown$3();
|
|
1788
1871
|
};
|
|
1789
1872
|
main$3();
|
|
1790
1873
|
|
|
@@ -1805,12 +1888,19 @@ const BEFORE_EXIT_FN$2 = singleshot(async () => {
|
|
|
1805
1888
|
});
|
|
1806
1889
|
listenDoneLive(cli.liveProviderService.disable);
|
|
1807
1890
|
});
|
|
1891
|
+
const listenGracefulShutdown$2 = singleshot(() => {
|
|
1892
|
+
process.on("SIGINT", BEFORE_EXIT_FN$2);
|
|
1893
|
+
});
|
|
1808
1894
|
const main$2 = async () => {
|
|
1895
|
+
if (!getEntry(import.meta.url)) {
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1809
1898
|
const { values } = getArgs();
|
|
1810
1899
|
if (!values.live) {
|
|
1811
1900
|
return;
|
|
1812
1901
|
}
|
|
1813
|
-
|
|
1902
|
+
await cli.liveMainService.connect();
|
|
1903
|
+
listenGracefulShutdown$2();
|
|
1814
1904
|
};
|
|
1815
1905
|
main$2();
|
|
1816
1906
|
|
|
@@ -1819,12 +1909,18 @@ const BEFORE_EXIT_FN$1 = singleshot(async () => {
|
|
|
1819
1909
|
notifyShutdown();
|
|
1820
1910
|
cli.frontendProviderService.disable();
|
|
1821
1911
|
});
|
|
1912
|
+
const listenGracefulShutdown$1 = singleshot(() => {
|
|
1913
|
+
process.on("SIGINT", BEFORE_EXIT_FN$1);
|
|
1914
|
+
});
|
|
1822
1915
|
const main$1 = async () => {
|
|
1916
|
+
if (!getEntry(import.meta.url)) {
|
|
1917
|
+
return;
|
|
1918
|
+
}
|
|
1823
1919
|
const { values } = getArgs();
|
|
1824
1920
|
if (!values.ui) {
|
|
1825
1921
|
return;
|
|
1826
1922
|
}
|
|
1827
|
-
|
|
1923
|
+
listenGracefulShutdown$1();
|
|
1828
1924
|
};
|
|
1829
1925
|
main$1();
|
|
1830
1926
|
|
|
@@ -1833,12 +1929,18 @@ const BEFORE_EXIT_FN = singleshot(async () => {
|
|
|
1833
1929
|
notifyShutdown();
|
|
1834
1930
|
cli.telegramProviderService.disable();
|
|
1835
1931
|
});
|
|
1932
|
+
const listenGracefulShutdown = singleshot(() => {
|
|
1933
|
+
process.on("SIGINT", BEFORE_EXIT_FN);
|
|
1934
|
+
});
|
|
1836
1935
|
const main = async () => {
|
|
1936
|
+
if (!getEntry(import.meta.url)) {
|
|
1937
|
+
return;
|
|
1938
|
+
}
|
|
1837
1939
|
const { values } = getArgs();
|
|
1838
1940
|
if (!values.telegram) {
|
|
1839
1941
|
return;
|
|
1840
1942
|
}
|
|
1841
|
-
|
|
1943
|
+
listenGracefulShutdown();
|
|
1842
1944
|
};
|
|
1843
1945
|
main();
|
|
1844
1946
|
|
|
@@ -1846,4 +1948,30 @@ function setLogger(logger) {
|
|
|
1846
1948
|
cli.loggerService.setLogger(logger);
|
|
1847
1949
|
}
|
|
1848
1950
|
|
|
1849
|
-
|
|
1951
|
+
let _is_started = false;
|
|
1952
|
+
async function run(mode, args) {
|
|
1953
|
+
{
|
|
1954
|
+
if (_is_started) {
|
|
1955
|
+
throw new Error("Should be called only once");
|
|
1956
|
+
}
|
|
1957
|
+
_is_started = true;
|
|
1958
|
+
}
|
|
1959
|
+
if (mode === "backtest") {
|
|
1960
|
+
await cli.backtestMainService.run(args);
|
|
1961
|
+
listenGracefulShutdown$4();
|
|
1962
|
+
return;
|
|
1963
|
+
}
|
|
1964
|
+
if (mode === "paper") {
|
|
1965
|
+
await cli.paperMainService.run(args);
|
|
1966
|
+
listenGracefulShutdown$3();
|
|
1967
|
+
return;
|
|
1968
|
+
}
|
|
1969
|
+
if (mode === "live") {
|
|
1970
|
+
await cli.liveMainService.run(args);
|
|
1971
|
+
listenGracefulShutdown$2();
|
|
1972
|
+
return;
|
|
1973
|
+
}
|
|
1974
|
+
throw new Error(`Invalid mode: ${mode}`);
|
|
1975
|
+
}
|
|
1976
|
+
|
|
1977
|
+
export { cli, run, setLogger };
|